From 975671639c6fcf7bfff112eab3e983e26baa2a6b Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Wed, 14 Jun 2023 15:38:11 +0100 Subject: [PATCH 001/148] dag: improve fuzzer Signed-off-by: AdamKorcz --- internal/dag/fuzz_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/internal/dag/fuzz_test.go b/internal/dag/fuzz_test.go index 5fd2e7d88..5449698f4 100644 --- a/internal/dag/fuzz_test.go +++ b/internal/dag/fuzz_test.go @@ -74,5 +74,21 @@ func FuzzDag(f *testing.F) { d := NewMapDag() _, _ = d.Init(toNodesFuzz(nodes)) + identifier, err := c.GetString() + if err != nil { + return + } + d.Sort() + _, _ = d.TraceNode(identifier) + d.Sort() + from, err := c.GetString() + if err != nil { + return + } + fuzzNode := &SimpleFuzzNode{} + c.GenerateStruct(fuzzNode) + _, _ = d.AddEdge(from, fuzzNode) + d.Sort() + d.NodeNeighbors(identifier) }) } From dbaf483663dea8198274d2bfa36214a22483bc40 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Wed, 14 Jun 2023 15:10:48 +0100 Subject: [PATCH 002/148] add revison fuzzer Signed-off-by: AdamKorcz --- internal/controller/pkg/revision/fuzz_test.go | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 internal/controller/pkg/revision/fuzz_test.go diff --git a/internal/controller/pkg/revision/fuzz_test.go b/internal/controller/pkg/revision/fuzz_test.go new file mode 100644 index 000000000..f605419ea --- /dev/null +++ b/internal/controller/pkg/revision/fuzz_test.go @@ -0,0 +1,142 @@ +/* +Copyright 2020 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package revision + +import ( + "bytes" + "context" + "errors" + "io" + "testing" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/crossplane/crossplane-runtime/pkg/parser" + "github.com/crossplane/crossplane-runtime/pkg/test" + + pkgmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1" + v1 "github.com/crossplane/crossplane/apis/pkg/v1" + "github.com/crossplane/crossplane/apis/pkg/v1beta1" + "github.com/crossplane/crossplane/internal/dag" + dagfake "github.com/crossplane/crossplane/internal/dag/fake" + "github.com/crossplane/crossplane/internal/xpkg" +) + +var ( + metaScheme *runtime.Scheme + objScheme *runtime.Scheme + linter = xpkg.NewProviderLinter() +) + +func init() { + var err error + metaScheme, err = xpkg.BuildMetaScheme() + if err != nil { + panic(err) + } + objScheme, err = xpkg.BuildObjectScheme() + if err != nil { + panic(err) + } +} + +func newFuzzDag(ff *fuzz.ConsumeFuzzer) (func() dag.DAG, error) { + traceNodeMap := make(map[string]dag.Node) + err := ff.FuzzMap(&traceNodeMap) + if err != nil { + return func() dag.DAG { return nil }, err + } + lp := &v1beta1.LockPackage{} + err = ff.GenerateStruct(lp) + if err != nil { + return func() dag.DAG { return nil }, err + } + return func() dag.DAG { + return &dagfake.MockDag{ + MockInit: func(nodes []dag.Node) ([]dag.Node, error) { + return nil, nil + }, + MockNodeExists: func(identifier string) bool { + return true + }, + MockTraceNode: func(_ string) (map[string]dag.Node, error) { + return traceNodeMap, nil + }, + MockGetNode: func(s string) (dag.Node, error) { + return lp, nil + }, + } + }, nil +} + +func getFuzzMockClient(ff *fuzz.ConsumeFuzzer) (*test.MockClient, error) { + lockPackages := make([]v1beta1.LockPackage, 0) + ff.CreateSlice(&lockPackages) + if len(lockPackages) == 0 { + return nil, errors.New("No packages created") + } + return &test.MockClient{ + MockGet: test.NewMockGetFn(nil, func(obj client.Object) error { + l := obj.(*v1beta1.Lock) + l.Packages = lockPackages + return nil + }), + MockUpdate: test.NewMockUpdateFn(nil), + }, nil +} + +func FuzzRevisionControllerPackageHandling(f *testing.F) { + f.Fuzz(func(t *testing.T, data, revisionData []byte) { + ff := fuzz.NewConsumer(revisionData) + p := parser.New(metaScheme, objScheme) + r := io.NopCloser(bytes.NewReader(data)) + pkg, err := p.Parse(context.Background(), r) + if err != nil { + return + } + if len(pkg.GetMeta()) == 0 { + return + } + if len(pkg.GetObjects()) == 0 { + return + } + prs := &v1.PackageRevisionSpec{} + ff.GenerateStruct(prs) + pr := &v1.ConfigurationRevision{Spec: *prs} + + if err := linter.Lint(pkg); err != nil { + return + } + pkgMeta, _ := xpkg.TryConvert(pkg.GetMeta()[0], &pkgmetav1.Provider{}, &pkgmetav1.Configuration{}) + c, err := getFuzzMockClient(ff) + if err != nil { + return + } + + fd, err := newFuzzDag(ff) + if err != nil { + return + } + pm := &PackageDependencyManager{ + client: c, + newDag: fd, + } + _, _, _, _ = pm.Resolve(context.Background(), pkgMeta, pr) + }) +} From 6626e54d77dfe9e5081b200872fb54e22197c529 Mon Sep 17 00:00:00 2001 From: Hasan Turken Date: Mon, 19 Jun 2023 09:10:21 +0300 Subject: [PATCH 003/148] Add one-pager for deletion ordering Signed-off-by: Hasan Turken --- design/one-pager-generic-usage-type.md | 397 +++++++++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 design/one-pager-generic-usage-type.md diff --git a/design/one-pager-generic-usage-type.md b/design/one-pager-generic-usage-type.md new file mode 100644 index 000000000..cc194a3fa --- /dev/null +++ b/design/one-pager-generic-usage-type.md @@ -0,0 +1,397 @@ +# Generic `Usage` Type for Deletion Ordering + +* Owner: Hasan Türken (@turkenh) +* Reviewers: @bobh66, @negz +* Status: Draft + +## Background + +Crossplane is built on Kubernetes, which leans into eventual consistency. When +several things need to happen in a particular order the "Kubernetes way" is to +specify the desired end state and rely on the relevant controllers to ensure the +system eventually arrives at that state, largely through the use of constant +reconciliation (aka retries). + +Take for example the creation of a VPC Network and a Subnet. The VPC must be +created and ready before a Subnet can be created within it. In Kubernetes, it’s +typical to request both resources be created at once (thereby declaring the +desired state). The creation of the Subnet will simply fail until its +dependency - the VPC - becomes available. + +This loosely coupled, eventually consistent approach is simple and resilient, +but it can appear chaotic. Operations must be attempted more times than would be +necessary in a "smarter" system, and often the temporarily failing operations +will emit warnings that may be confusing or concerning to the uninitiated. Some +other systems - notably Terraform - avoid this by computing a dependency graph +before attempting to enact the desired state. This allows the system to avoid +trying operations it knows will fail due to missing dependencies until those +dependencies are expected to be satisfied. + +A frequent negative side-effect of the eventually consistent approach that we +see in Crossplane is resources becoming orphaned at delete time because their +successful deletion depends on the existence of other resources which are often +deleted before their dependents. It’s possible to author a set of interdependent +resources that will eventually create successfully, but may not eventually +delete successfully. + +Two variants of this problem are: + +- **Orphaned Managed Resources (MRs).** Consider a Helm Release MR that is +deployed to an EKS Cluster MR. The Helm Release has a dependency on the EKS +Cluster’s connection details - it uses them as Provider credentials. If the EKS +Cluster is deleted before the Helm Release the Helm Release controller becomes +unable to connect to its Provider in order to delete the Release. In practice +the Release External Resource (ER) was implicitly deleted along with the GKE +Cluster - there’s actually no work left for the Helm release controller to do - +but it cannot know that. This results in the Helm Release MR being ‘orphaned’ +in a pending deletion that can never be satisfied. + +- **Orphaned ‘Side-Effect’ Resources.** Consider the same example as above, and +assume the Helm Release includes a Kubernetes Service resource of type: +LoadBalancer. A side-effect of the creation of this Service will be to create an +ELB in the EKS cluster’s VPC. This ELB is not managed by or even known to +Crossplane, and is not deleted along with the EKS cluster. This means that the +Helm Release (and therefore its Service) must be deleted before the EKS cluster +in order to ensure the EKS cluster’s controllers trigger deletion of the ELB. +If it is not, the ELB will be orphaned, costing money and blocking the deletion +of the VPC it was created in. + +These problems are exacerbated by the fact that Kubernetes uses "background +cascading deletion" by default. Put otherwise, the successful deletion of a +parent resource is not dependent on the successful deletion of its children. +Instead, the parent resource will be deleted successfully and the children +(i.e. resources that declare the parent as an owner reference) will later be +deleted by the Kubernetes garbage collector. This makes it difficult to diagnose +or even notice resources that become orphaned when their parent XR is deleted. + +## Goals + +- Support "cross-provider" dependencies, for example an MR from provider-helm +depending on a ProviderConfig from provider-aws. +- Don’t require Crossplane users to manage fine-grained RBAC access. +- Don’t grant Crossplane providers broad RBAC access (e.g. to all other providers). + +## Proposal + +We propose introducing a new `Usage` type that can be used to declare usage +relationships between Crossplane resources. This type will be defined by the +Core Crossplane repository, and be available for use as part of a composition. + +The relations defined by this type will be enforced by an admission webhook that +will be running as part of the Crossplane core. Similar to the upstreams [liens +proposal], the webhook will reject deletions of resources that are in use by +other resources with a ["409 Conflict" error code]. + +### API + +We will introduce a new `Usage` type as follows: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: Usage +metadata: + name: release-uses-cluster +spec: + of: + - apiVersion: eks.upbound.io/v1beta1 + kind: Cluster + name: my-cluster + by: + apiVersion: helm.crossplane.io/v1beta1 + kind: Release + name: my-prometheus-chart +``` + +The `spec.by` field will define the resource that will be using the resources +defined in `spec.of`. Both will support only cluster-scoped resources, namely +`Composites` and `Managed Resources`. + +In this example, we define a usage relationship between a Helm `Release` and an +EKS `Cluster`. The deletion of the `Cluster` resource will be rejected as long +as this `Release` resource exists. + +In addition to direct referencing with names, we will also support selectors to +match labels or controller reference. This will allow us to define usage +relationships between resources created by the same composition instance. + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: Usage +metadata: + name: release-uses-cluster +spec: + of: + - apiVersion: eks.upbound.io/v1beta1 + kind: Cluster + selector: + matchControllerRef: true + by: + apiVersion: helm.crossplane.io/v1beta1 + kind: Release + selector: + matchControllerRef: true +``` + +While the well-known use cases for this feature are solved with a one-to-one +usage relationship, we will support one-to-many relationship +(i.e. `spec.of` as a list) as well, considering it provides more flexibility +without introducing additional complexity to the implementation. + +### Implementation + +The implementation of this feature will be done in two parts: + +1. The `Usage` type and its controller, which will manage the lifecycle of the + resource. +2. The admission webhook that will enforce the usage relationships. + +Both will be implemented in the Crossplane core repository and would not require +any changes in the providers. + +#### Usage Controller + +The usage controller will be responsible for managing the lifecycle of the usage +relationship by: + +- Resolving selectors, if any. +- Adding owner reference from the using resource (i.e., `spec.by`) to the `Usage`. +- Preventing deletion of `Usage` before the using resource is deleted. +- Adding or removing admission webhook rules to intercept the `DELETE` requests + for the used resource(s). + +**Resolving selectors:** + +The API will support defining selectors for both the using and used resources. +Initially, we will only support resolving references with the following rules: + +- Resolution will be made once when the `Usage` is created. +- If multiple resources match the selector, a random one will be + selected. + +The [existing policies] for resolving Managed Resource references does not +necessarily apply to the `Usage`. For example, supporting an `optional` +reference while defining a usage relationship does not make sense. Also, the +[reasoning behind] supporting different policies for MRs does not apply to +the `Usage`. However, depending on the feedback, we may consider supporting +resolve policies to configure whether the resolution should be made once or +continuously in a future iteration. + +**Adding owner reference:** + +We want the `Usage` to be deleted when the using resource is deleted. This will +be achieved by adding an owner reference from the using resource to the `Usage`. + +**Preventing early deletion of the `Usage`:** + +Typically, we expect a `Usage` resource to be defined as part of the same +composition as the using and used resources. This means the `Usage` will get +the delete request when the composite resource is deleted. In this case, the +controller will prevent the deletion of the `Usage` until the using resource is +deleted with the help of a finalizer. + +**Defining admission webhook rules:** + +The admission webhook will intercept the `DELETE` requests for the used +resource(s). To achieve this, the controller will add [webhook rules] for the +used resource(s) when a `Usage` is created. It is also the controller's job to +remove these rules when the `Usage` is deleted, and no other `Usage` resources +reference the same used resource(s). + +#### Admission Webhook + +The admission webhook will be responsible for intercepting the `DELETE` requests +for the used resource(s) and rejecting them with a ["409 Conflict" error code]. + +The webhook will be implemented as a Kubernetes validating admission webhook +leveraging the [existing webhook machinery] in Crossplane and will be running +as part of the Crossplane core. + +We will use the [Field Indexers] to efficiently query the used resource(s) when +a `DELETE` request is received. + +Implementation of the core logic for the webhook handler: + +```go +func (h *handler) validateNoUsages(ctx context.Context, u *unstructured.Unstructured) admission.Response { + usageList := &v1alpha1.UsageList{} + if err := h.reader.List(ctx, usageList, client.MatchingFields{inUseIndexKey: getIndexValueForObject(u)}); err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } + if len(usageList.Items) > 0 { + return admission.Response{ + AdmissionResponse: admissionv1.AdmissionResponse{ + Allowed: false, + Result: &metav1.Status{ + Code: int32(http.StatusConflict), + Reason: metav1.StatusReason(fmt.Sprintf("The resource is used by %s/%s", usageList.Items[0].Spec.By.Kind, usageList.Items[0].Spec.By.Name)), + }, + }, + } + } + return admission.Allowed("") +} +``` + +### User Experience + +**Defining a Usage Resource as part of a Composition:** + +We expect a typical usage relationship to be defined as part of the same +composition as the using and used resources. In this case, the user will +define the `Usage` resource as part of the composition template. + +Let's take [upbound/platform-ref-aws] as an example. In this composition, we +have a [composition for `XCluster`] which composes `XEKS` composing an EKS cluster, +and `XServices` composing a set of helm releases running on the cluster. In this +case, we will add the following resource to the same composition to define a +usage relationship between the `XServices` and the `XEKS` Composites: + +```yaml + - name: xservices-uses-xeks + base: + apiVersion: apiextensions.crossplane.io/v1alpha1 + kind: Usage + spec: + of: + - apiVersion: aws.platformref.upbound.io/v1alpha1 + kind: XEKS + selector: + matchControllerRef: true + by: + apiVersion: aws.platformref.upbound.io/v1alpha1 + kind: XServices + selector: + matchControllerRef: true +``` + +**Deleting a Claim or Composite which contains a Usage Relationship:** + +**With the (default) background propagation policy**, we expect no different in user +experience. Users will be able to delete the Claim or Composite without any error. +The Claim or Composite will be deleted immediately, and the Kubernetes garbage +collector will delete the Composed Resources together with the `Usage` resources +in the background. It will take longer until all Composed Resources are garbage +collected, however this will not be visible to the user. + +**With the foreground propagation policy**, the only difference we expect is +that the deletion is taking longer than before. The user will be able to delete +the Claim or Composite without any error. The deletion of the Claim or Composite +will be blocked until all Composed Resources are deleted as before. It will take +longer because deletion of the used resource will be blocked until the used +resource hence `Usage` is deleted. + +> One caveat with the garbage collector is the substantial delay it can cause +during the deletion of composites. This delay caused by the garbage collector's +use of an exponential backoff when the DELETE API call is rejected. The maximum +backoff time is 1000 seconds, which means that after no usage of an object is +left, it could take up to 1000 seconds before the garbage collector attempts to +delete the resource that was previously blocked. To mitigate this issue, we +could introduce a mechanism in the controller to re-trigger the deletion of the +used resource as soon as the Usage resource is deleted. + +**Directly Deleting a Composite or Managed Resource that is in Use** + +When trying to delete a Composite or managed resource directly, users will get +an error as follows: + +```bash +Error from server (The resource is used by Release/my-release): error when deleting "my-cluster.yaml": admission webhook "nousages.apiextensions.crossplane.io" denied the request: The resource is used by Release/my-release +``` + +From the error message, it is clear that the resource is in use by a `Release` +resource. The user can then delete the `Release` resource and then delete the +Composite or managed resource again. + +## Alternatives Considered + +### Prior Art + +Some alternatives considered in this [previous document], namely: + +- Assume Implicit Deletion +- In-use Liens +- Composition-internal Dependencies +- Composition-ordered Dependencies +- Introduce a Global Dependency Object +- Introduce a Scoped Dependency Object +- Model Dependencies in Spec +- Dependent-managed Finalizers + +Please see that document for further details on each of these alternatives. + +Among these alternatives, this proposal focuses on the +"Introduce a Global Dependency Object" option but with some implementation +differences which are explained in detail in the following section. + +### Alternative Implementations with a Global `Usage` Object + +There are three distinct types of resources that we want to block the deletion +of when used by other resources: + +1. A Managed Resource. + - We control the deletion logic; we have the most power. + - We can use an annotation or finalizer (or whatever we want) and handle the + logic in managed reconciler for all managed resources, e.g., do not delete + the external resource if the managed resource is in use. +2. A Composite Resource with the (default) background deletion policy. + - We rely on the garbage collector for deletion. Composed Resources got the + deletion request only after the Composite disappeared from the API. + - So, we can still rely on a finalizer-based approach to block the deletion + of the whole tree of owned (Composed) Resources. +3. A Composite Resource but with the foreground deletion policy. + - We still rely on the garbage collector for deletion; however, Composed + Resources got the deletion request immediately after the Composite got the + deletion request, no matter whether it has additional finalizers or not. + - Finalizer-based approaches wouldn't work out of the box. + +So, we have three possible solutions to cover all the scenarios: + +**Option A:** Block the delete request with the help of a webhook in any case. + +**Option B:** When there is a dependency on a Composite Resource, resolve that +dependency down to all Composed Resources and only implement deletion prevention +logic for the Managed Resources. + +**Option C:** For Composite resources, do not rely on the garbage collector by +removing owner references to delete Composed Resources and implement our custom +deletion logic. + +Option C is not ideal because it requires us to implement our custom deletion +logic for Composites, and will break the tools using owner references +(e.g. ArgoCD) to track the relationship between Composites and Composed +Resources. + +If we try to make a comparison between the other two approaches: + +| | Option A: Webhook & Reject Delete Requests | Option B: Delay Deletion Until No Usage with Resolved `Usages` | +|-------------------|--------------------------------------------|----------------------------------------| +| Implementation Complexity | Easier to implement, fewer complexities to handle during development. | More complex to implement due to the need to _continuously_ resolve dependencies to XRs down to nested XRs and MRs . | +| User Experience | Provides immediate feedback, but users need to manually retry deletion after all usages are gone. | Users do not need to manually retry deletions, which may be smoother, but the delay in deletion might be confusing if not properly communicated. | +| Alignment with the Kubernetes Philosophy | Aligned with Kubernetes' Liens KEP (still open), which advocates for proactive protection against deletion. | Aligned with Kubernetes' philosophy of eventual consistency and the existing behavior of PV/PVC protection and Crossplane ProviderConfigUsage. | +| Scalability | Scales better since it will require one `Usage` per XR. | Ends up with multiple `Usages` per XR and can grow quickly when there are nested XRs or multiple dependencies on the same parent. | +| User Error Protection | The upfront rejection of deletion requests can prevent accidental deletion when there are still usages. | While deletion will eventually occur when all usages are gone, there could be a risk of unintended consequences during the delay period. | +| Debugging/Troubleshooting | Easier to debug since only `Usage`s created by the user exists, and resources won't have deletion timestamp. | More difficult to debug since further `Usage`s created by the controllers, and it is not easy to identify whether a resource is being deleted or waiting for dependencies to be gone at a given moment. | +| Ease of Rollout | Easier, only requires changes in the XP repo. | Requires changes in XP, runtime, and providers needs to be updated. | + +Especially considering that there is no clear agreement in upstream, we +believe _it could be good to choose a practical approach and start with the +simpler solution, namely the webhook-based solution_. We think it's better to +start with the simple option, and then, if we find out that it's not enough, we +can think about changing to a more complex solution. If we check the above table, +it is clear that the webhook-based solution is the simpler one. + +If we decide to change the underlying implementation later, we don't expect +an API change except getting rejected deletes vs. not. This also provides us a +good opportunity to test the webhook-based solution in the field and gather +feedback from the community before committing to a more complex solution. + +[liens proposal]: https://github.com/kubernetes/enhancements/pull/2840 +["409 Conflict" error code]: https://datatracker.ietf.org/doc/html/rfc2616#section-10.4.10 +[existing policies]: https://github.com/crossplane/crossplane-runtime/blob/23eaff94e7385121bca832955c8885f925f55ae6/apis/common/v1/resource.go#L80 +[reasoning behind]: https://github.com/crossplane/crossplane-runtime/pull/328 +[webhook rules]: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-rules +[existing webhook machinery]: https://github.com/crossplane/crossplane/pull/2919 +[Field Indexers]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/client#FieldIndexer +[previous document]: https://docs.google.com/document/d/1Yu3GxNMJOOMWMjD6gEw5QtT8Fz5qQSyo18ZZFKqcqKw +[upbound/platform-ref-aws]: https://github.com/upbound/platform-ref-aws/tree/v0.6.0 +[composition for `XCluster`]: https://github.com/upbound/platform-ref-aws/blob/v0.6.0/package/cluster/composition.yaml \ No newline at end of file From 312b91718fe130cf2122c396a773bddbf52f2d18 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Sat, 17 Jun 2023 16:44:34 +0100 Subject: [PATCH 004/148] composite: add fuzzer Signed-off-by: AdamKorcz --- .../apiextensions/composite/fuzz_test.go | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/controller/apiextensions/composite/fuzz_test.go b/internal/controller/apiextensions/composite/fuzz_test.go index b5cc2fe27..62b1c2c47 100644 --- a/internal/controller/apiextensions/composite/fuzz_test.go +++ b/internal/controller/apiextensions/composite/fuzz_test.go @@ -21,9 +21,13 @@ import ( "testing" fuzz "github.com/AdaLogics/go-fuzz-headers" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/yaml" + "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource/fake" + "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composite" v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" pkgmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1" @@ -145,3 +149,40 @@ func FuzzTransform(f *testing.F) { _, _ = Resolve(*t, i) }) } + +func YamlToUnstructured(yamlStr string) (*unstructured.Unstructured, error) { + obj := make(map[string]interface{}) + err := yaml.Unmarshal([]byte(yamlStr), &obj) + if err != nil { + return nil, err + } + return &unstructured.Unstructured{Object: obj}, nil +} + +func FuzzPTFComposer(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte, yamlData string) { + ff := fuzz.NewConsumer(data) + state := &PTFCompositionState{} + unstr, err := YamlToUnstructured(yamlData) + if err != nil { + return + } + if unstr.Object == nil { + return + } + state.Composite = &composite.Unstructured{Unstructured: *unstr} + cd := &managed.ConnectionDetails{} + ff.GenerateStruct(cd) + state.ConnectionDetails = *cd + _, err = FunctionIOObserved(state) + if err != nil { + return + } + + _, err = FunctionIODesired(state) + if err != nil { + return + } + UpdateResourceRefs(state) + }) +} From e2716c42ace94bfc5b7d4f47e8ae562e26ad1aeb Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 22 Jun 2023 09:39:55 +0200 Subject: [PATCH 005/148] chore: linting Signed-off-by: Philippe Scorsolini --- internal/dag/fuzz_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/dag/fuzz_test.go b/internal/dag/fuzz_test.go index 5449698f4..40eb101cc 100644 --- a/internal/dag/fuzz_test.go +++ b/internal/dag/fuzz_test.go @@ -87,7 +87,7 @@ func FuzzDag(f *testing.F) { } fuzzNode := &SimpleFuzzNode{} c.GenerateStruct(fuzzNode) - _, _ = d.AddEdge(from, fuzzNode) + _, _ = d.AddEdge(from, fuzzNode) d.Sort() d.NodeNeighbors(identifier) }) From 1e38ec880ed741a1d0de87251d9540102324b0a0 Mon Sep 17 00:00:00 2001 From: Hasan Turken Date: Thu, 22 Jun 2023 13:09:17 +0300 Subject: [PATCH 006/148] Resolve comments in Usage one pager Signed-off-by: Hasan Turken --- design/one-pager-generic-usage-type.md | 27 +++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/design/one-pager-generic-usage-type.md b/design/one-pager-generic-usage-type.md index cc194a3fa..ed9e3466d 100644 --- a/design/one-pager-generic-usage-type.md +++ b/design/one-pager-generic-usage-type.md @@ -41,7 +41,7 @@ deployed to an EKS Cluster MR. The Helm Release has a dependency on the EKS Cluster’s connection details - it uses them as Provider credentials. If the EKS Cluster is deleted before the Helm Release the Helm Release controller becomes unable to connect to its Provider in order to delete the Release. In practice -the Release External Resource (ER) was implicitly deleted along with the GKE +the Release External Resource (ER) was implicitly deleted along with the EKS Cluster - there’s actually no work left for the Helm release controller to do - but it cannot know that. This results in the Helm Release MR being ‘orphaned’ in a pending deletion that can never be satisfied. @@ -75,12 +75,18 @@ depending on a ProviderConfig from provider-aws. We propose introducing a new `Usage` type that can be used to declare usage relationships between Crossplane resources. This type will be defined by the -Core Crossplane repository, and be available for use as part of a composition. +Core Crossplane repository, and also be available for use as part of a +composition. The relations defined by this type will be enforced by an admission webhook that will be running as part of the Crossplane core. Similar to the upstreams [liens proposal], the webhook will reject deletions of resources that are in use by -other resources with a ["409 Conflict" error code]. +other resources with a ["409 Conflict" error code] as `metav1.Status` as part of +the admission response (not the actual http code of the admission request). + +The RBAC manager already grants Crossplane RBAC access to all types in order for +it to do Composition. Therefore, there's no need for extra RBAC permissions to +interact with resources across providers. ### API @@ -125,11 +131,15 @@ spec: kind: Cluster selector: matchControllerRef: true + matchLabels: + foo: bar by: apiVersion: helm.crossplane.io/v1beta1 kind: Release selector: matchControllerRef: true + matchLabels: + baz: qux ``` While the well-known use cases for this feature are solved with a one-to-one @@ -201,6 +211,8 @@ reference the same used resource(s). The admission webhook will be responsible for intercepting the `DELETE` requests for the used resource(s) and rejecting them with a ["409 Conflict" error code]. +We will fail open in case of any errors from the webhook with +[`failurePolicy: Fail`]. The webhook will be implemented as a Kubernetes validating admission webhook leveraging the [existing webhook machinery] in Crossplane and will be running @@ -223,7 +235,7 @@ func (h *handler) validateNoUsages(ctx context.Context, u *unstructured.Unstruct Allowed: false, Result: &metav1.Status{ Code: int32(http.StatusConflict), - Reason: metav1.StatusReason(fmt.Sprintf("The resource is used by %s/%s", usageList.Items[0].Spec.By.Kind, usageList.Items[0].Spec.By.Name)), + Reason: metav1.StatusReason(fmt.Sprintf("The resource is used by %d resource(s), including %s/%s", len(usageList.Items), usageList.Items[0].Spec.By.Kind, usageList.Items[0].Spec.By.Name)), }, }, } @@ -234,7 +246,7 @@ func (h *handler) validateNoUsages(ctx context.Context, u *unstructured.Unstruct ### User Experience -**Defining a Usage Resource as part of a Composition:** +#### Defining a Usage Resource as part of a Composition We expect a typical usage relationship to be defined as part of the same composition as the using and used resources. In this case, the user will @@ -264,7 +276,7 @@ usage relationship between the `XServices` and the `XEKS` Composites: matchControllerRef: true ``` -**Deleting a Claim or Composite which contains a Usage Relationship:** +#### Deleting a Claim or Composite which contains a Usage Relationship **With the (default) background propagation policy**, we expect no different in user experience. Users will be able to delete the Claim or Composite without any error. @@ -289,7 +301,7 @@ delete the resource that was previously blocked. To mitigate this issue, we could introduce a mechanism in the controller to re-trigger the deletion of the used resource as soon as the Usage resource is deleted. -**Directly Deleting a Composite or Managed Resource that is in Use** +#### Directly Deleting a Composite or Managed Resource that is in Use When trying to delete a Composite or managed resource directly, users will get an error as follows: @@ -390,6 +402,7 @@ feedback from the community before committing to a more complex solution. [existing policies]: https://github.com/crossplane/crossplane-runtime/blob/23eaff94e7385121bca832955c8885f925f55ae6/apis/common/v1/resource.go#L80 [reasoning behind]: https://github.com/crossplane/crossplane-runtime/pull/328 [webhook rules]: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-rules +[`failurePolicy: Fail`]: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy [existing webhook machinery]: https://github.com/crossplane/crossplane/pull/2919 [Field Indexers]: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/client#FieldIndexer [previous document]: https://docs.google.com/document/d/1Yu3GxNMJOOMWMjD6gEw5QtT8Fz5qQSyo18ZZFKqcqKw From 4b4100cb7836ffc09a145a6b66058ab338592335 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 17:53:14 +0000 Subject: [PATCH 007/148] Update docker/setup-buildx-action digest to 16c0bc4 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd06ed575..5aec3d972 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -249,7 +249,7 @@ jobs: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2 + uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true @@ -311,7 +311,7 @@ jobs: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2 + uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true From 70e4e94c73eb23465b024cd98dedb9e0731e9559 Mon Sep 17 00:00:00 2001 From: Bob Haddleton Date: Wed, 28 Jun 2023 09:57:04 -0500 Subject: [PATCH 008/148] Add registry option for xfn Signed-off-by: Bob Haddleton --- cmd/crossplane/core/core.go | 1 + cmd/xfn/main.go | 13 +++++++++++-- cmd/xfn/run/run.go | 7 ++++--- cmd/xfn/spark/spark.go | 5 +++-- cmd/xfn/start/start.go | 10 ++++++++-- .../apiextensions/composite/composition_ptf.go | 4 ++-- .../composite/composition_ptf_test.go | 4 +++- .../apiextensions/controller/options.go | 4 ++++ .../apiextensions/definition/reconciler.go | 2 +- internal/xfn/container.go | 17 +++++++++++++---- internal/xfn/container_linux.go | 4 ++-- 11 files changed, 52 insertions(+), 19 deletions(-) diff --git a/cmd/crossplane/core/core.go b/cmd/crossplane/core/core.go index d4b1d5a7a..50d8e3a5d 100644 --- a/cmd/crossplane/core/core.go +++ b/cmd/crossplane/core/core.go @@ -214,6 +214,7 @@ func (c *startCommand) Run(s *runtime.Scheme, log logging.Logger) error { //noli Options: o, Namespace: c.Namespace, ServiceAccount: c.ServiceAccount, + Registry: c.Registry, } if err := apiextensions.Setup(mgr, ao); err != nil { diff --git a/cmd/xfn/main.go b/cmd/xfn/main.go index 0f1229431..25fab67fb 100644 --- a/cmd/xfn/main.go +++ b/cmd/xfn/main.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/alecthomas/kong" + "github.com/google/go-containerregistry/pkg/name" "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/crossplane/crossplane-runtime/pkg/logging" @@ -34,10 +35,17 @@ import ( type debugFlag bool type versionFlag bool +// KongVars represent the kong variables associated with the CLI parser +// required for the Registry default variable interpolation. +var KongVars = kong.Vars{ + "default_registry": name.DefaultRegistry, +} + var cli struct { Debug debugFlag `short:"d" help:"Print verbose logging statements."` - Version versionFlag `short:"v" help:"Print version and quit."` + Version versionFlag `short:"v" help:"Print version and quit."` + Registry string `short:"r" help:"Default registry used to fetch containers when not specified in tag." default:"${default_registry}" env:"REGISTRY"` Start start.Command `cmd:"" help:"Start listening for Composition Function runs over gRPC." default:"1"` Run run.Command `cmd:"" help:"Run a Composition Function."` @@ -69,6 +77,7 @@ func main() { kong.Description("Crossplane Composition Functions."), kong.BindTo(logging.NewLogrLogger(zl), (*logging.Logger)(nil)), kong.UsageOnError(), + KongVars, ) - ctx.FatalIfErrorf(ctx.Run()) + ctx.FatalIfErrorf(ctx.Run(&start.Args{Registry: cli.Registry})) } diff --git a/cmd/xfn/run/run.go b/cmd/xfn/run/run.go index c2699bf58..e1efae90e 100644 --- a/cmd/xfn/run/run.go +++ b/cmd/xfn/run/run.go @@ -30,6 +30,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1alpha1" + "github.com/crossplane/crossplane/cmd/xfn/start" "github.com/crossplane/crossplane/internal/xfn" ) @@ -59,7 +60,7 @@ type Command struct { } // Run a Composition container function. -func (c *Command) Run() error { +func (c *Command) Run(args *start.Args) error { // If we don't have CAP_SETUID or CAP_SETGID, we'll only be able to map our // own UID and GID to root inside the user namespace. rootUID := os.Getuid() @@ -70,7 +71,7 @@ func (c *Command) Run() error { rootGID = c.MapRootGID } - ref, err := name.ParseReference(c.Image) + ref, err := name.ParseReference(c.Image, name.WithDefaultRegistry(args.Registry)) if err != nil { return errors.Wrap(err, errParseImage) } @@ -90,7 +91,7 @@ func (c *Command) Run() error { return errors.Wrap(err, errAuthCfg) } - f := xfn.NewContainerRunner(xfn.SetUID(setuid), xfn.MapToRoot(rootUID, rootGID), xfn.WithCacheDir(filepath.Clean(c.CacheDir))) + f := xfn.NewContainerRunner(xfn.SetUID(setuid), xfn.MapToRoot(rootUID, rootGID), xfn.WithCacheDir(filepath.Clean(c.CacheDir)), xfn.WithRegistry(args.Registry)) rsp, err := f.RunFunction(context.Background(), &v1alpha1.RunFunctionRequest{ Image: c.Image, Input: c.FunctionIO, diff --git a/cmd/xfn/spark/spark.go b/cmd/xfn/spark/spark.go index 32c4f70b7..7c4984bb2 100644 --- a/cmd/xfn/spark/spark.go +++ b/cmd/xfn/spark/spark.go @@ -35,6 +35,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1alpha1" + "github.com/crossplane/crossplane/cmd/xfn/start" "github.com/crossplane/crossplane/internal/oci" "github.com/crossplane/crossplane/internal/oci/spec" "github.com/crossplane/crossplane/internal/oci/store" @@ -79,7 +80,7 @@ type Command struct { // Run a Composition Function inside an unprivileged user namespace. Reads a // protocol buffer serialized RunFunctionRequest from stdin, and writes a // protocol buffer serialized RunFunctionResponse to stdout. -func (c *Command) Run() error { //nolint:gocyclo // TODO(negz): Refactor some of this out into functions, add tests. +func (c *Command) Run(args *start.Args) error { //nolint:gocyclo // TODO(negz): Refactor some of this out into functions, add tests. pb, err := io.ReadAll(os.Stdin) if err != nil { return errors.Wrap(err, errReadRequest) @@ -121,7 +122,7 @@ func (c *Command) Run() error { //nolint:gocyclo // TODO(negz): Refactor some of return errors.Wrap(err, errNewDigestStore) } - r, err := name.ParseReference(req.GetImage()) + r, err := name.ParseReference(req.GetImage(), name.WithDefaultRegistry(args.Registry)) if err != nil { return errors.Wrap(err, errParseRef) } diff --git a/cmd/xfn/start/start.go b/cmd/xfn/start/start.go index 3b6e35bf6..921335df8 100644 --- a/cmd/xfn/start/start.go +++ b/cmd/xfn/start/start.go @@ -33,6 +33,11 @@ const ( errListenAndServe = "cannot listen for and serve gRPC API" ) +// Args contains the default registry used to pull XFN containers. +type Args struct { + Registry string +} + // Command starts a gRPC API to run Composition Functions. type Command struct { CacheDir string `short:"c" help:"Directory used for caching function images and containers." default:"/xfn"` @@ -43,7 +48,7 @@ type Command struct { } // Run a Composition Function gRPC API. -func (c *Command) Run(log logging.Logger) error { +func (c *Command) Run(args *Args, log logging.Logger) error { // If we don't have CAP_SETUID or CAP_SETGID, we'll only be able to map our // own UID and GID to root inside the user namespace. rootUID := os.Getuid() @@ -59,6 +64,7 @@ func (c *Command) Run(log logging.Logger) error { xfn.SetUID(setuid), xfn.MapToRoot(rootUID, rootGID), xfn.WithCacheDir(filepath.Clean(c.CacheDir)), - xfn.WithLogger(log)) + xfn.WithLogger(log), + xfn.WithRegistry(args.Registry)) return errors.Wrap(f.ListenAndServe(c.Network, c.Address), errListenAndServe) } diff --git a/internal/controller/apiextensions/composite/composition_ptf.go b/internal/controller/apiextensions/composite/composition_ptf.go index f01ac8dd9..84d22e7cb 100644 --- a/internal/controller/apiextensions/composite/composition_ptf.go +++ b/internal/controller/apiextensions/composite/composition_ptf.go @@ -649,7 +649,7 @@ type ContainerFunctionRunnerOption func(ctx context.Context, fn *v1.ContainerFun // 2. Loads credentials from the supplied service account's image pull secrets. // 3. Loads credentials from the function's image pull secrets. // 4. Loads credentials using the GKE, EKS, or AKS credentials helper. -func WithKubernetesAuthentication(c client.Reader, namespace, serviceAccount string) ContainerFunctionRunnerOption { +func WithKubernetesAuthentication(c client.Reader, namespace, serviceAccount string, registry string) ContainerFunctionRunnerOption { return func(ctx context.Context, fn *v1.ContainerFunction, r *fnv1alpha1.RunFunctionRequest) error { sa := &corev1.ServiceAccount{} @@ -677,7 +677,7 @@ func WithKubernetesAuthentication(c client.Reader, namespace, serviceAccount str return errors.Wrap(err, errNewKeychain) } - ref, err := name.ParseReference(fn.Image) + ref, err := name.ParseReference(fn.Image, name.WithDefaultRegistry(registry)) if err != nil { return errors.Wrap(err, errParseImage) } diff --git a/internal/controller/apiextensions/composite/composition_ptf_test.go b/internal/controller/apiextensions/composite/composition_ptf_test.go index 0a71b3a42..fa928a38d 100644 --- a/internal/controller/apiextensions/composite/composition_ptf_test.go +++ b/internal/controller/apiextensions/composite/composition_ptf_test.go @@ -1117,6 +1117,7 @@ func TestWithKubernetesAuthentication(t *testing.T) { c client.Reader namespace string serviceAccount string + registry string } type args struct { ctx context.Context @@ -1188,6 +1189,7 @@ func TestWithKubernetesAuthentication(t *testing.T) { return nil }, }, + registry: "index.docker.io", }, args: args{ fn: &v1.ContainerFunction{ @@ -1211,7 +1213,7 @@ func TestWithKubernetesAuthentication(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { - err := WithKubernetesAuthentication(tc.params.c, tc.params.namespace, tc.params.serviceAccount)(tc.args.ctx, tc.args.fn, tc.args.r) + err := WithKubernetesAuthentication(tc.params.c, tc.params.namespace, tc.params.serviceAccount, tc.params.registry)(tc.args.ctx, tc.args.fn, tc.args.r) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { t.Errorf("\n%s\nWithKubernetesAuthentication(...): -want error, +got error:\n%s", tc.reason, diff) diff --git a/internal/controller/apiextensions/controller/options.go b/internal/controller/apiextensions/controller/options.go index f951da9c0..6f06b4868 100644 --- a/internal/controller/apiextensions/controller/options.go +++ b/internal/controller/apiextensions/controller/options.go @@ -32,4 +32,8 @@ type Options struct { // ServiceAccount for which we'll find image pull secrets for in-cluster // private registry authentication when pulling Composition Functions. ServiceAccount string + + // Registry is the default registry to use when pulling containers for + // Composition Functions + Registry string } diff --git a/internal/controller/apiextensions/definition/reconciler.go b/internal/controller/apiextensions/definition/reconciler.go index 67078ebea..3a135143f 100644 --- a/internal/controller/apiextensions/definition/reconciler.go +++ b/internal/controller/apiextensions/definition/reconciler.go @@ -505,7 +505,7 @@ func CompositeReconcilerOptions(co apiextensionscontroller.Options, d *v1.Compos composite.WithCompositeConnectionDetailsFetcher(fetcher), composite.WithFunctionPipelineRunner(composite.NewFunctionPipeline( composite.ContainerFunctionRunnerFn(composite.RunFunction), - composite.WithKubernetesAuthentication(c, co.Namespace, co.ServiceAccount), + composite.WithKubernetesAuthentication(c, co.Namespace, co.ServiceAccount, co.Registry), )), ), composite.NewPTComposer(c, composite.WithComposedConnectionDetailsFetcher(fetcher)), diff --git a/internal/xfn/container.go b/internal/xfn/container.go index 461a991ce..b6351ec58 100644 --- a/internal/xfn/container.go +++ b/internal/xfn/container.go @@ -43,10 +43,11 @@ type ContainerRunner struct { log logging.Logger - rootUID int - rootGID int - setuid bool // Specifically, CAP_SETUID and CAP_SETGID. - cache string + rootUID int + rootGID int + setuid bool // Specifically, CAP_SETUID and CAP_SETGID. + cache string + registry string } // A ContainerRunnerOption configures a new ContainerRunner. @@ -78,6 +79,14 @@ func WithCacheDir(d string) ContainerRunnerOption { } } +// WithRegistry specifies the default registry used to retrieve function images and +// containers. +func WithRegistry(dr string) ContainerRunnerOption { + return func(r *ContainerRunner) { + r.registry = dr + } +} + // WithLogger configures which logger the container runner should use. Logging // is disabled by default. func WithLogger(l logging.Logger) ContainerRunnerOption { diff --git a/internal/xfn/container_linux.go b/internal/xfn/container_linux.go index 675198830..2605652cc 100644 --- a/internal/xfn/container_linux.go +++ b/internal/xfn/container_linux.go @@ -95,10 +95,10 @@ func (r *ContainerRunner) RunFunction(ctx context.Context, req *v1alpha1.RunFunc Therefore we execute a shim - xfn spark - in a new user and mount namespace. spark fetches and caches the image, creates an OCI runtime - bundle, then then executes an OCI runtime in order to actually execute + bundle, then executes an OCI runtime in order to actually execute the function. */ - cmd := exec.CommandContext(ctx, os.Args[0], spark, "--cache-dir="+r.cache, fmt.Sprintf("--max-stdio-bytes=%d", MaxStdioBytes)) //nolint:gosec // We're intentionally executing with variable input. + cmd := exec.CommandContext(ctx, os.Args[0], spark, "--cache-dir="+r.cache, "--registry="+r.registry, fmt.Sprintf("--max-stdio-bytes=%d", MaxStdioBytes)) //nolint:gosec // We're intentionally executing with variable input. cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUSER | syscall.CLONE_NEWNS, UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: r.rootUID, Size: 1}}, From 6df4a9bb739aa27043476fa81f78ea5f007c8cf3 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Wed, 28 Jun 2023 18:12:23 -0700 Subject: [PATCH 009/148] Update module google.golang.org/protobuf to v1.31.0 This required running `make reviewable`. Signed-off-by: Nic Cope --- apis/apiextensions/fn/proto/v1alpha1/run_function.pb.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apis/apiextensions/fn/proto/v1alpha1/run_function.pb.go b/apis/apiextensions/fn/proto/v1alpha1/run_function.pb.go index 82d0e7e1c..8929c75e5 100644 --- a/apis/apiextensions/fn/proto/v1alpha1/run_function.pb.go +++ b/apis/apiextensions/fn/proto/v1alpha1/run_function.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc (unknown) // source: apiextensions/fn/proto/v1alpha1/run_function.proto diff --git a/go.mod b/go.mod index c39d75acd..969e61643 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( golang.org/x/sys v0.9.0 google.golang.org/grpc v1.56.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 k8s.io/api v0.27.3 k8s.io/apiextensions-apiserver v0.27.3 k8s.io/apimachinery v0.27.3 diff --git a/go.sum b/go.sum index 08fe9603d..615e75dd9 100644 --- a/go.sum +++ b/go.sum @@ -898,8 +898,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From cff50692282419218ec2076807d68b62f5be0318 Mon Sep 17 00:00:00 2001 From: nullable-eth <2248325+nullable-eth@users.noreply.github.com> Date: Thu, 29 Jun 2023 08:07:44 -0400 Subject: [PATCH 010/148] add function types Signed-off-by: nullable-eth <2248325+nullable-eth@users.noreply.github.com> --- apis/pkg/meta/v1alpha1/function_types.go | 37 ++++++++++ apis/pkg/meta/v1alpha1/register.go | 9 +++ .../meta/v1alpha1/zz_generated.deepcopy.go | 42 +++++++++++ .../meta.pkg.crossplane.io_functions.yaml | 74 +++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 apis/pkg/meta/v1alpha1/function_types.go create mode 100644 cluster/meta/meta.pkg.crossplane.io_functions.yaml diff --git a/apis/pkg/meta/v1alpha1/function_types.go b/apis/pkg/meta/v1alpha1/function_types.go new file mode 100644 index 000000000..a105a34ac --- /dev/null +++ b/apis/pkg/meta/v1alpha1/function_types.go @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// FunctionSpec specifies the configuration of a Function. +type FunctionSpec struct { + MetaSpec `json:",inline"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:storageversion + +// A Function is the description of a Crossplane Function package. +type Function struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FunctionSpec `json:"spec"` +} diff --git a/apis/pkg/meta/v1alpha1/register.go b/apis/pkg/meta/v1alpha1/register.go index 41f37e2c0..0447e11f2 100644 --- a/apis/pkg/meta/v1alpha1/register.go +++ b/apis/pkg/meta/v1alpha1/register.go @@ -56,7 +56,16 @@ var ( ConfigurationGroupVersionKind = SchemeGroupVersion.WithKind(ConfigurationKind) ) +// Function type metadata. +var ( + FunctionKind = reflect.TypeOf(Function{}).Name() + FunctionGroupKind = schema.GroupKind{Group: Group, Kind: FunctionKind}.String() + FunctionKindAPIVersion = FunctionKind + "." + SchemeGroupVersion.String() + FunctionGroupVersionKind = SchemeGroupVersion.WithKind(FunctionKind) +) + func init() { SchemeBuilder.Register(&Configuration{}) SchemeBuilder.Register(&Provider{}) + SchemeBuilder.Register(&Function{}) } diff --git a/apis/pkg/meta/v1alpha1/zz_generated.deepcopy.go b/apis/pkg/meta/v1alpha1/zz_generated.deepcopy.go index 69b78ee36..5f449bc7b 100644 --- a/apis/pkg/meta/v1alpha1/zz_generated.deepcopy.go +++ b/apis/pkg/meta/v1alpha1/zz_generated.deepcopy.go @@ -135,6 +135,48 @@ func (in *Dependency) DeepCopy() *Dependency { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Function) DeepCopyInto(out *Function) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. +func (in *Function) DeepCopy() *Function { + if in == nil { + return nil + } + out := new(Function) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Function) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) { + *out = *in + in.MetaSpec.DeepCopyInto(&out.MetaSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec. +func (in *FunctionSpec) DeepCopy() *FunctionSpec { + if in == nil { + return nil + } + out := new(FunctionSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GeneratedFromHubConverter) DeepCopyInto(out *GeneratedFromHubConverter) { *out = *in diff --git a/cluster/meta/meta.pkg.crossplane.io_functions.yaml b/cluster/meta/meta.pkg.crossplane.io_functions.yaml new file mode 100644 index 000000000..f03a8146d --- /dev/null +++ b/cluster/meta/meta.pkg.crossplane.io_functions.yaml @@ -0,0 +1,74 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.0 + name: functions.meta.pkg.crossplane.io +spec: + group: meta.pkg.crossplane.io + names: + kind: Function + listKind: FunctionList + plural: functions + singular: function + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: A Function is the description of a Crossplane Function package. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: FunctionSpec specifies the configuration of a Function. + properties: + crossplane: + description: Semantic version constraints of Crossplane that package + is compatible with. + properties: + version: + description: Semantic version constraints of Crossplane that package + is compatible with. + type: string + required: + - version + type: object + dependsOn: + description: Dependencies on other packages. + items: + description: Dependency is a dependency on another package. One + of Provider or Configuration may be supplied. + properties: + configuration: + description: Configuration is the name of a Configuration package + image. + type: string + provider: + description: Provider is the name of a Provider package image. + type: string + version: + description: Version is the semantic version constraints of + the dependency image. + type: string + required: + - version + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true From d3a7e39e9264a23c29c3a7dd7f9ae6ba097937cf Mon Sep 17 00:00:00 2001 From: nullable-eth <2248325+nullable-eth@users.noreply.github.com> Date: Thu, 29 Jun 2023 09:08:22 -0400 Subject: [PATCH 011/148] fix conversion and add test Signed-off-by: nullable-eth <2248325+nullable-eth@users.noreply.github.com> --- apis/pkg/meta/v1alpha1/conversion.go | 34 ++++++ .../meta/v1alpha1/zz_generated.conversion.go | 110 ++++++++++++++++++ internal/xpkg/lint.go | 11 ++ internal/xpkg/lint_test.go | 35 ++++++ 4 files changed, 190 insertions(+) diff --git a/apis/pkg/meta/v1alpha1/conversion.go b/apis/pkg/meta/v1alpha1/conversion.go index 995f67021..3880fb69f 100644 --- a/apis/pkg/meta/v1alpha1/conversion.go +++ b/apis/pkg/meta/v1alpha1/conversion.go @@ -30,6 +30,9 @@ const ( errWrongConvertToProvider = "must convert to *v1.Provider" errWrongConvertFromProvider = "must convert from *v1.Provider" + + errWrongConvertToFunction = "must convert to *v1alpha1.Function" + errWrongConvertFromFunction = "must convert from *v1alpha1.Function" ) // A ToHubConverter converts v1alpha1 types to the 'hub' v1 type. @@ -41,6 +44,7 @@ const ( type ToHubConverter interface { Configuration(in *Configuration) *v1.Configuration Provider(in *Provider) *v1.Provider + Function(in *Function) *Function } // A FromHubConverter converts v1alpha1 types from the 'hub' v1 type. @@ -52,6 +56,7 @@ type ToHubConverter interface { type FromHubConverter interface { Configuration(in *v1.Configuration) *Configuration Provider(in *v1.Provider) *Provider + Function(in *Function) *Function } // ConvertObjectMeta 'converts' ObjectMeta by producing a deepcopy. This @@ -113,3 +118,32 @@ func (p *Provider) ConvertFrom(hub conversion.Hub) error { return nil } + +// Hub marks this type as the conversion hub. +func (f *Function) Hub() {} + +// ConvertTo converts this Function to the Hub version. +func (f *Function) ConvertTo(hub conversion.Hub) error { + out, ok := hub.(*Function) + if !ok { + return errors.New(errWrongConvertToFunction) + } + + conv := &GeneratedToHubConverter{} + *out = *conv.Function(f) + + return nil +} + +// ConvertFrom converts this Function from the Hub version. +func (f *Function) ConvertFrom(hub conversion.Hub) error { + in, ok := hub.(*Function) + if !ok { + return errors.New(errWrongConvertFromFunction) + } + + conv := &GeneratedFromHubConverter{} + *f = *conv.Function(in) + + return nil +} diff --git a/apis/pkg/meta/v1alpha1/zz_generated.conversion.go b/apis/pkg/meta/v1alpha1/zz_generated.conversion.go index 68bdf17ea..93b09f3f8 100755 --- a/apis/pkg/meta/v1alpha1/zz_generated.conversion.go +++ b/apis/pkg/meta/v1alpha1/zz_generated.conversion.go @@ -21,6 +21,17 @@ func (c *GeneratedFromHubConverter) Configuration(source *v1.Configuration) *Con } return pV1alpha1Configuration } +func (c *GeneratedFromHubConverter) Function(source *Function) *Function { + var pV1alpha1Function *Function + if source != nil { + var v1alpha1Function Function + v1alpha1Function.TypeMeta = c.v1TypeMetaToV1TypeMeta((*source).TypeMeta) + v1alpha1Function.ObjectMeta = ConvertObjectMeta((*source).ObjectMeta) + v1alpha1Function.Spec = c.v1alpha1FunctionSpecToV1alpha1FunctionSpec((*source).Spec) + pV1alpha1Function = &v1alpha1Function + } + return pV1alpha1Function +} func (c *GeneratedFromHubConverter) Provider(source *v1.Provider) *Provider { var pV1alpha1Provider *Provider if source != nil { @@ -41,6 +52,15 @@ func (c *GeneratedFromHubConverter) pV1CrossplaneConstraintsToPV1alpha1Crossplan } return pV1alpha1CrossplaneConstraints } +func (c *GeneratedFromHubConverter) pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source *CrossplaneConstraints) *CrossplaneConstraints { + var pV1alpha1CrossplaneConstraints *CrossplaneConstraints + if source != nil { + var v1alpha1CrossplaneConstraints CrossplaneConstraints + v1alpha1CrossplaneConstraints.Version = (*source).Version + pV1alpha1CrossplaneConstraints = &v1alpha1CrossplaneConstraints + } + return pV1alpha1CrossplaneConstraints +} func (c *GeneratedFromHubConverter) v1ConfigurationSpecToV1alpha1ConfigurationSpec(source v1.ConfigurationSpec) ConfigurationSpec { var v1alpha1ConfigurationSpec ConfigurationSpec v1alpha1ConfigurationSpec.MetaSpec = c.v1MetaSpecToV1alpha1MetaSpec(source.MetaSpec) @@ -150,6 +170,41 @@ func (c *GeneratedFromHubConverter) v1TypeMetaToV1TypeMeta(source v12.TypeMeta) v1TypeMeta.APIVersion = source.APIVersion return v1TypeMeta } +func (c *GeneratedFromHubConverter) v1alpha1DependencyToV1alpha1Dependency(source Dependency) Dependency { + var v1alpha1Dependency Dependency + var pString *string + if source.Provider != nil { + xstring := *source.Provider + pString = &xstring + } + v1alpha1Dependency.Provider = pString + var pString2 *string + if source.Configuration != nil { + xstring2 := *source.Configuration + pString2 = &xstring2 + } + v1alpha1Dependency.Configuration = pString2 + v1alpha1Dependency.Version = source.Version + return v1alpha1Dependency +} +func (c *GeneratedFromHubConverter) v1alpha1FunctionSpecToV1alpha1FunctionSpec(source FunctionSpec) FunctionSpec { + var v1alpha1FunctionSpec FunctionSpec + v1alpha1FunctionSpec.MetaSpec = c.v1alpha1MetaSpecToV1alpha1MetaSpec(source.MetaSpec) + return v1alpha1FunctionSpec +} +func (c *GeneratedFromHubConverter) v1alpha1MetaSpecToV1alpha1MetaSpec(source MetaSpec) MetaSpec { + var v1alpha1MetaSpec MetaSpec + v1alpha1MetaSpec.Crossplane = c.pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source.Crossplane) + var v1alpha1DependencyList []Dependency + if source.DependsOn != nil { + v1alpha1DependencyList = make([]Dependency, len(source.DependsOn)) + for i := 0; i < len(source.DependsOn); i++ { + v1alpha1DependencyList[i] = c.v1alpha1DependencyToV1alpha1Dependency(source.DependsOn[i]) + } + } + v1alpha1MetaSpec.DependsOn = v1alpha1DependencyList + return v1alpha1MetaSpec +} type GeneratedToHubConverter struct{} @@ -164,6 +219,17 @@ func (c *GeneratedToHubConverter) Configuration(source *Configuration) *v1.Confi } return pV1Configuration } +func (c *GeneratedToHubConverter) Function(source *Function) *Function { + var pV1alpha1Function *Function + if source != nil { + var v1alpha1Function Function + v1alpha1Function.TypeMeta = c.v1TypeMetaToV1TypeMeta((*source).TypeMeta) + v1alpha1Function.ObjectMeta = ConvertObjectMeta((*source).ObjectMeta) + v1alpha1Function.Spec = c.v1alpha1FunctionSpecToV1alpha1FunctionSpec((*source).Spec) + pV1alpha1Function = &v1alpha1Function + } + return pV1alpha1Function +} func (c *GeneratedToHubConverter) Provider(source *Provider) *v1.Provider { var pV1Provider *v1.Provider if source != nil { @@ -184,6 +250,15 @@ func (c *GeneratedToHubConverter) pV1alpha1CrossplaneConstraintsToPV1CrossplaneC } return pV1CrossplaneConstraints } +func (c *GeneratedToHubConverter) pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source *CrossplaneConstraints) *CrossplaneConstraints { + var pV1alpha1CrossplaneConstraints *CrossplaneConstraints + if source != nil { + var v1alpha1CrossplaneConstraints CrossplaneConstraints + v1alpha1CrossplaneConstraints.Version = (*source).Version + pV1alpha1CrossplaneConstraints = &v1alpha1CrossplaneConstraints + } + return pV1alpha1CrossplaneConstraints +} func (c *GeneratedToHubConverter) v1PolicyRuleToV1PolicyRule(source v11.PolicyRule) v11.PolicyRule { var v1PolicyRule v11.PolicyRule var stringList []string @@ -274,6 +349,28 @@ func (c *GeneratedToHubConverter) v1alpha1DependencyToV1Dependency(source Depend v1Dependency.Version = source.Version return v1Dependency } +func (c *GeneratedToHubConverter) v1alpha1DependencyToV1alpha1Dependency(source Dependency) Dependency { + var v1alpha1Dependency Dependency + var pString *string + if source.Provider != nil { + xstring := *source.Provider + pString = &xstring + } + v1alpha1Dependency.Provider = pString + var pString2 *string + if source.Configuration != nil { + xstring2 := *source.Configuration + pString2 = &xstring2 + } + v1alpha1Dependency.Configuration = pString2 + v1alpha1Dependency.Version = source.Version + return v1alpha1Dependency +} +func (c *GeneratedToHubConverter) v1alpha1FunctionSpecToV1alpha1FunctionSpec(source FunctionSpec) FunctionSpec { + var v1alpha1FunctionSpec FunctionSpec + v1alpha1FunctionSpec.MetaSpec = c.v1alpha1MetaSpecToV1alpha1MetaSpec(source.MetaSpec) + return v1alpha1FunctionSpec +} func (c *GeneratedToHubConverter) v1alpha1MetaSpecToV1MetaSpec(source MetaSpec) v1.MetaSpec { var v1MetaSpec v1.MetaSpec v1MetaSpec.Crossplane = c.pV1alpha1CrossplaneConstraintsToPV1CrossplaneConstraints(source.Crossplane) @@ -287,6 +384,19 @@ func (c *GeneratedToHubConverter) v1alpha1MetaSpecToV1MetaSpec(source MetaSpec) v1MetaSpec.DependsOn = v1DependencyList return v1MetaSpec } +func (c *GeneratedToHubConverter) v1alpha1MetaSpecToV1alpha1MetaSpec(source MetaSpec) MetaSpec { + var v1alpha1MetaSpec MetaSpec + v1alpha1MetaSpec.Crossplane = c.pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source.Crossplane) + var v1alpha1DependencyList []Dependency + if source.DependsOn != nil { + v1alpha1DependencyList = make([]Dependency, len(source.DependsOn)) + for i := 0; i < len(source.DependsOn); i++ { + v1alpha1DependencyList[i] = c.v1alpha1DependencyToV1alpha1Dependency(source.DependsOn[i]) + } + } + v1alpha1MetaSpec.DependsOn = v1alpha1DependencyList + return v1alpha1MetaSpec +} func (c *GeneratedToHubConverter) v1alpha1ProviderSpecToV1ProviderSpec(source ProviderSpec) v1.ProviderSpec { var v1ProviderSpec v1.ProviderSpec v1ProviderSpec.Controller = c.v1alpha1ControllerSpecToV1ControllerSpec(source.Controller) diff --git a/internal/xpkg/lint.go b/internal/xpkg/lint.go index 158bcf0b3..34e43a43d 100644 --- a/internal/xpkg/lint.go +++ b/internal/xpkg/lint.go @@ -28,6 +28,7 @@ import ( v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" pkgmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1" + pkgmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1" "github.com/crossplane/crossplane/internal/version" ) @@ -36,6 +37,7 @@ const ( errNotMeta = "meta type is not a package" errNotMetaProvider = "package meta type is not Provider" errNotMetaConfiguration = "package meta type is not Configuration" + errNotMetaFunction = "package meta type is not Function" errNotCRD = "object is not a CRD" errNotXRD = "object is not an XRD" errNotMutatingWebhookConfiguration = "object is not a MutatingWebhookConfiguration" @@ -88,6 +90,15 @@ func IsConfiguration(o runtime.Object) error { return nil } +// IsFunction checks that an object is a Function meta type. +func IsFunction(o runtime.Object) error { + po, _ := TryConvert(o, &pkgmetav1alpha1.Function{}) + if _, ok := po.(*pkgmetav1alpha1.Function); !ok { + return errors.New(errNotMetaFunction) + } + return nil +} + // PackageCrossplaneCompatible checks that the current Crossplane version is // compatible with the package constraints. func PackageCrossplaneCompatible(v version.Operations) parser.ObjectLinterFn { diff --git a/internal/xpkg/lint_test.go b/internal/xpkg/lint_test.go index bed163a4d..cdbce8cd4 100644 --- a/internal/xpkg/lint_test.go +++ b/internal/xpkg/lint_test.go @@ -60,6 +60,11 @@ kind: Configuration metadata: name: test`) + v1alpha1FuncBytes = []byte(`apiVersion: meta.pkg.crossplane.io/v1 + kind: Function + metadata: + name: test`) + v1ProvBytes = []byte(`apiVersion: meta.pkg.crossplane.io/v1 kind: Provider metadata: @@ -88,6 +93,8 @@ metadata: _ = yaml.Unmarshal(v1alpha1ProvBytes, v1alpha1ProvMeta) v1alpha1ConfMeta = &pkgmetav1alpha1.Configuration{} _ = yaml.Unmarshal(v1alpha1ConfBytes, v1alpha1ConfMeta) + v1alpha1FuncMeta = &pkgmetav1alpha1.Function{} + _ = yaml.Unmarshal(v1alpha1FuncBytes, v1alpha1FuncMeta) v1ProvMeta = &pkgmetav1.Provider{} _ = yaml.Unmarshal(v1ProvBytes, v1ProvMeta) v1ConfMeta = &pkgmetav1.Configuration{} @@ -206,6 +213,34 @@ func TestIsConfiguration(t *testing.T) { } } +func TestIsFunction(t *testing.T) { + cases := map[string]struct { + reason string + obj runtime.Object + err error + }{ + "v1alpha1": { + reason: "Should not return error if object is a v1alpha1 function.", + obj: v1alpha1FuncMeta, + }, + "ErrNotFunction": { + reason: "Should return error if object is not function.", + obj: v1beta1crd, + err: errors.New(errNotMetaFunction), + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err := IsFunction(tc.obj) + + if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" { + t.Errorf("\n%s\nIsFunction(...): -want error, +got error:\n%s", tc.reason, diff) + } + }) + } +} + func TestPackageCrossplaneCompatible(t *testing.T) { crossplaneConstraint := ">v0.13.0" errBoom := errors.New("boom") From 7591bb0e48b23b13657ae7ca6014cd115e0d6967 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Thu, 29 Jun 2023 15:28:34 +0100 Subject: [PATCH 012/148] Fix issue in fuzzer and dag Signed-off-by: AdamKorcz --- internal/dag/dag.go | 3 +++ internal/dag/fuzz_test.go | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/internal/dag/dag.go b/internal/dag/dag.go index 5dc2b9ec6..39f14a20b 100644 --- a/internal/dag/dag.go +++ b/internal/dag/dag.go @@ -213,6 +213,9 @@ func (d *MapDag) visit(name string, neighbors []Node, stack map[string]bool, vis stack[name] = true for _, n := range neighbors { if !visited[n.Identifier()] { + if _, ok := d.nodes[n.Identifier()]; !ok { + return errors.Errorf("node does not exist") + } if err := d.visit(n.Identifier(), d.nodes[n.Identifier()].Neighbors(), stack, visited, results); err != nil { return err } diff --git a/internal/dag/fuzz_test.go b/internal/dag/fuzz_test.go index 40eb101cc..5d7700ae8 100644 --- a/internal/dag/fuzz_test.go +++ b/internal/dag/fuzz_test.go @@ -43,6 +43,9 @@ func (s *SimpleFuzzNode) AddNeighbors(nodes ...Node) error { if !ok { return errors.New("not a simple node") } + if s.NeighborsField == nil { + s.NeighborsField = make(map[string]SimpleFuzzNode) + } s.NeighborsField[sn.Identifier()] = *sn } return nil @@ -71,6 +74,11 @@ func FuzzDag(f *testing.F) { if err != nil { return } + for _, n := range nodes { + if n.NeighborsField == nil { + n.NeighborsField = make(map[string]SimpleFuzzNode) + } + } d := NewMapDag() _, _ = d.Init(toNodesFuzz(nodes)) From 65041589d1ff378c1e061cd3f59382608c13a8c6 Mon Sep 17 00:00:00 2001 From: nullable-eth <2248325+nullable-eth@users.noreply.github.com> Date: Thu, 29 Jun 2023 14:53:50 -0400 Subject: [PATCH 013/148] fix copyright and add convenience linter function Signed-off-by: nullable-eth <2248325+nullable-eth@users.noreply.github.com> --- apis/pkg/meta/v1alpha1/function_types.go | 2 +- internal/xpkg/lint.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apis/pkg/meta/v1alpha1/function_types.go b/apis/pkg/meta/v1alpha1/function_types.go index a105a34ac..b87d6c01c 100644 --- a/apis/pkg/meta/v1alpha1/function_types.go +++ b/apis/pkg/meta/v1alpha1/function_types.go @@ -1,5 +1,5 @@ /* -Copyright 2020 The Crossplane Authors. +Copyright 2023 The Crossplane Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/xpkg/lint.go b/internal/xpkg/lint.go index 34e43a43d..b4bfbf34c 100644 --- a/internal/xpkg/lint.go +++ b/internal/xpkg/lint.go @@ -64,6 +64,12 @@ func NewConfigurationLinter() parser.Linter { return parser.NewPackageLinter(parser.PackageLinterFns(OneMeta), parser.ObjectLinterFns(IsConfiguration, PackageValidSemver), parser.ObjectLinterFns(parser.Or(IsXRD, IsComposition))) } +// NewFunctionLinter is a convenience function for creating a package linter for +// functions. +func NewFunctionLinter() parser.Linter { + return parser.NewPackageLinter(parser.PackageLinterFns(OneMeta), parser.ObjectLinterFns(IsFunction, PackageValidSemver), parser.ObjectLinterFns()) +} + // OneMeta checks that there is only one meta object in the package. func OneMeta(pkg *parser.Package) error { if len(pkg.GetMeta()) != 1 { From e5607f294282b7fd976a5391823609b827591dbb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Jun 2023 23:24:34 +0000 Subject: [PATCH 014/148] Update module github.com/bufbuild/buf to v1.23.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c39d75acd..e84b89979 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 - github.com/bufbuild/buf v1.22.0 + github.com/bufbuild/buf v1.23.0 github.com/crossplane/crossplane-runtime v0.20.0-rc.0.0.20230622044456-2dfb8bc6bfbc github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 diff --git a/go.sum b/go.sum index 08fe9603d..d4e68955d 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,8 @@ github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bufbuild/buf v1.22.0 h1:dCWUIx1gm3nm5U+FKdkVjaL+Rk9Ev3hh4XYMa2Cbn/o= -github.com/bufbuild/buf v1.22.0/go.mod h1:ERFRzJiIjAOzUSJ3vz1zoI7XfxlBnCwZEyL+NJm4pko= +github.com/bufbuild/buf v1.23.0 h1:QD6xCygtCVhN6qsQ4TtE2xGRK86xGkjI9lNHJ5jaj+M= +github.com/bufbuild/buf v1.23.0/go.mod h1:ERFRzJiIjAOzUSJ3vz1zoI7XfxlBnCwZEyL+NJm4pko= github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc= github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk= From 860f9542cfa155714e80dc47feec7d03acde57fa Mon Sep 17 00:00:00 2001 From: "nullable.eth" <2248325+nullable-eth@users.noreply.github.com> Date: Fri, 30 Jun 2023 09:44:37 -0400 Subject: [PATCH 015/148] modify IsFunction check to be able to remove conversion code Co-authored-by: Nic Cope Signed-off-by: nullable.eth <2248325+nullable-eth@users.noreply.github.com> --- internal/xpkg/lint.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/xpkg/lint.go b/internal/xpkg/lint.go index b4bfbf34c..1e4ccbbd6 100644 --- a/internal/xpkg/lint.go +++ b/internal/xpkg/lint.go @@ -98,8 +98,7 @@ func IsConfiguration(o runtime.Object) error { // IsFunction checks that an object is a Function meta type. func IsFunction(o runtime.Object) error { - po, _ := TryConvert(o, &pkgmetav1alpha1.Function{}) - if _, ok := po.(*pkgmetav1alpha1.Function); !ok { + if _, ok := o.(*pkgmetav1alpha1.Function); !ok { return errors.New(errNotMetaFunction) } return nil From 2c7b47e709b53e7685ff5fb740fee4a283703692 Mon Sep 17 00:00:00 2001 From: nullable-eth <2248325+nullable-eth@users.noreply.github.com> Date: Fri, 30 Jun 2023 09:54:09 -0400 Subject: [PATCH 016/148] remove function conversion code Signed-off-by: nullable-eth <2248325+nullable-eth@users.noreply.github.com> --- apis/pkg/meta/v1alpha1/conversion.go | 34 ------ .../meta/v1alpha1/zz_generated.conversion.go | 110 ------------------ 2 files changed, 144 deletions(-) diff --git a/apis/pkg/meta/v1alpha1/conversion.go b/apis/pkg/meta/v1alpha1/conversion.go index 3880fb69f..995f67021 100644 --- a/apis/pkg/meta/v1alpha1/conversion.go +++ b/apis/pkg/meta/v1alpha1/conversion.go @@ -30,9 +30,6 @@ const ( errWrongConvertToProvider = "must convert to *v1.Provider" errWrongConvertFromProvider = "must convert from *v1.Provider" - - errWrongConvertToFunction = "must convert to *v1alpha1.Function" - errWrongConvertFromFunction = "must convert from *v1alpha1.Function" ) // A ToHubConverter converts v1alpha1 types to the 'hub' v1 type. @@ -44,7 +41,6 @@ const ( type ToHubConverter interface { Configuration(in *Configuration) *v1.Configuration Provider(in *Provider) *v1.Provider - Function(in *Function) *Function } // A FromHubConverter converts v1alpha1 types from the 'hub' v1 type. @@ -56,7 +52,6 @@ type ToHubConverter interface { type FromHubConverter interface { Configuration(in *v1.Configuration) *Configuration Provider(in *v1.Provider) *Provider - Function(in *Function) *Function } // ConvertObjectMeta 'converts' ObjectMeta by producing a deepcopy. This @@ -118,32 +113,3 @@ func (p *Provider) ConvertFrom(hub conversion.Hub) error { return nil } - -// Hub marks this type as the conversion hub. -func (f *Function) Hub() {} - -// ConvertTo converts this Function to the Hub version. -func (f *Function) ConvertTo(hub conversion.Hub) error { - out, ok := hub.(*Function) - if !ok { - return errors.New(errWrongConvertToFunction) - } - - conv := &GeneratedToHubConverter{} - *out = *conv.Function(f) - - return nil -} - -// ConvertFrom converts this Function from the Hub version. -func (f *Function) ConvertFrom(hub conversion.Hub) error { - in, ok := hub.(*Function) - if !ok { - return errors.New(errWrongConvertFromFunction) - } - - conv := &GeneratedFromHubConverter{} - *f = *conv.Function(in) - - return nil -} diff --git a/apis/pkg/meta/v1alpha1/zz_generated.conversion.go b/apis/pkg/meta/v1alpha1/zz_generated.conversion.go index 93b09f3f8..68bdf17ea 100755 --- a/apis/pkg/meta/v1alpha1/zz_generated.conversion.go +++ b/apis/pkg/meta/v1alpha1/zz_generated.conversion.go @@ -21,17 +21,6 @@ func (c *GeneratedFromHubConverter) Configuration(source *v1.Configuration) *Con } return pV1alpha1Configuration } -func (c *GeneratedFromHubConverter) Function(source *Function) *Function { - var pV1alpha1Function *Function - if source != nil { - var v1alpha1Function Function - v1alpha1Function.TypeMeta = c.v1TypeMetaToV1TypeMeta((*source).TypeMeta) - v1alpha1Function.ObjectMeta = ConvertObjectMeta((*source).ObjectMeta) - v1alpha1Function.Spec = c.v1alpha1FunctionSpecToV1alpha1FunctionSpec((*source).Spec) - pV1alpha1Function = &v1alpha1Function - } - return pV1alpha1Function -} func (c *GeneratedFromHubConverter) Provider(source *v1.Provider) *Provider { var pV1alpha1Provider *Provider if source != nil { @@ -52,15 +41,6 @@ func (c *GeneratedFromHubConverter) pV1CrossplaneConstraintsToPV1alpha1Crossplan } return pV1alpha1CrossplaneConstraints } -func (c *GeneratedFromHubConverter) pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source *CrossplaneConstraints) *CrossplaneConstraints { - var pV1alpha1CrossplaneConstraints *CrossplaneConstraints - if source != nil { - var v1alpha1CrossplaneConstraints CrossplaneConstraints - v1alpha1CrossplaneConstraints.Version = (*source).Version - pV1alpha1CrossplaneConstraints = &v1alpha1CrossplaneConstraints - } - return pV1alpha1CrossplaneConstraints -} func (c *GeneratedFromHubConverter) v1ConfigurationSpecToV1alpha1ConfigurationSpec(source v1.ConfigurationSpec) ConfigurationSpec { var v1alpha1ConfigurationSpec ConfigurationSpec v1alpha1ConfigurationSpec.MetaSpec = c.v1MetaSpecToV1alpha1MetaSpec(source.MetaSpec) @@ -170,41 +150,6 @@ func (c *GeneratedFromHubConverter) v1TypeMetaToV1TypeMeta(source v12.TypeMeta) v1TypeMeta.APIVersion = source.APIVersion return v1TypeMeta } -func (c *GeneratedFromHubConverter) v1alpha1DependencyToV1alpha1Dependency(source Dependency) Dependency { - var v1alpha1Dependency Dependency - var pString *string - if source.Provider != nil { - xstring := *source.Provider - pString = &xstring - } - v1alpha1Dependency.Provider = pString - var pString2 *string - if source.Configuration != nil { - xstring2 := *source.Configuration - pString2 = &xstring2 - } - v1alpha1Dependency.Configuration = pString2 - v1alpha1Dependency.Version = source.Version - return v1alpha1Dependency -} -func (c *GeneratedFromHubConverter) v1alpha1FunctionSpecToV1alpha1FunctionSpec(source FunctionSpec) FunctionSpec { - var v1alpha1FunctionSpec FunctionSpec - v1alpha1FunctionSpec.MetaSpec = c.v1alpha1MetaSpecToV1alpha1MetaSpec(source.MetaSpec) - return v1alpha1FunctionSpec -} -func (c *GeneratedFromHubConverter) v1alpha1MetaSpecToV1alpha1MetaSpec(source MetaSpec) MetaSpec { - var v1alpha1MetaSpec MetaSpec - v1alpha1MetaSpec.Crossplane = c.pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source.Crossplane) - var v1alpha1DependencyList []Dependency - if source.DependsOn != nil { - v1alpha1DependencyList = make([]Dependency, len(source.DependsOn)) - for i := 0; i < len(source.DependsOn); i++ { - v1alpha1DependencyList[i] = c.v1alpha1DependencyToV1alpha1Dependency(source.DependsOn[i]) - } - } - v1alpha1MetaSpec.DependsOn = v1alpha1DependencyList - return v1alpha1MetaSpec -} type GeneratedToHubConverter struct{} @@ -219,17 +164,6 @@ func (c *GeneratedToHubConverter) Configuration(source *Configuration) *v1.Confi } return pV1Configuration } -func (c *GeneratedToHubConverter) Function(source *Function) *Function { - var pV1alpha1Function *Function - if source != nil { - var v1alpha1Function Function - v1alpha1Function.TypeMeta = c.v1TypeMetaToV1TypeMeta((*source).TypeMeta) - v1alpha1Function.ObjectMeta = ConvertObjectMeta((*source).ObjectMeta) - v1alpha1Function.Spec = c.v1alpha1FunctionSpecToV1alpha1FunctionSpec((*source).Spec) - pV1alpha1Function = &v1alpha1Function - } - return pV1alpha1Function -} func (c *GeneratedToHubConverter) Provider(source *Provider) *v1.Provider { var pV1Provider *v1.Provider if source != nil { @@ -250,15 +184,6 @@ func (c *GeneratedToHubConverter) pV1alpha1CrossplaneConstraintsToPV1CrossplaneC } return pV1CrossplaneConstraints } -func (c *GeneratedToHubConverter) pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source *CrossplaneConstraints) *CrossplaneConstraints { - var pV1alpha1CrossplaneConstraints *CrossplaneConstraints - if source != nil { - var v1alpha1CrossplaneConstraints CrossplaneConstraints - v1alpha1CrossplaneConstraints.Version = (*source).Version - pV1alpha1CrossplaneConstraints = &v1alpha1CrossplaneConstraints - } - return pV1alpha1CrossplaneConstraints -} func (c *GeneratedToHubConverter) v1PolicyRuleToV1PolicyRule(source v11.PolicyRule) v11.PolicyRule { var v1PolicyRule v11.PolicyRule var stringList []string @@ -349,28 +274,6 @@ func (c *GeneratedToHubConverter) v1alpha1DependencyToV1Dependency(source Depend v1Dependency.Version = source.Version return v1Dependency } -func (c *GeneratedToHubConverter) v1alpha1DependencyToV1alpha1Dependency(source Dependency) Dependency { - var v1alpha1Dependency Dependency - var pString *string - if source.Provider != nil { - xstring := *source.Provider - pString = &xstring - } - v1alpha1Dependency.Provider = pString - var pString2 *string - if source.Configuration != nil { - xstring2 := *source.Configuration - pString2 = &xstring2 - } - v1alpha1Dependency.Configuration = pString2 - v1alpha1Dependency.Version = source.Version - return v1alpha1Dependency -} -func (c *GeneratedToHubConverter) v1alpha1FunctionSpecToV1alpha1FunctionSpec(source FunctionSpec) FunctionSpec { - var v1alpha1FunctionSpec FunctionSpec - v1alpha1FunctionSpec.MetaSpec = c.v1alpha1MetaSpecToV1alpha1MetaSpec(source.MetaSpec) - return v1alpha1FunctionSpec -} func (c *GeneratedToHubConverter) v1alpha1MetaSpecToV1MetaSpec(source MetaSpec) v1.MetaSpec { var v1MetaSpec v1.MetaSpec v1MetaSpec.Crossplane = c.pV1alpha1CrossplaneConstraintsToPV1CrossplaneConstraints(source.Crossplane) @@ -384,19 +287,6 @@ func (c *GeneratedToHubConverter) v1alpha1MetaSpecToV1MetaSpec(source MetaSpec) v1MetaSpec.DependsOn = v1DependencyList return v1MetaSpec } -func (c *GeneratedToHubConverter) v1alpha1MetaSpecToV1alpha1MetaSpec(source MetaSpec) MetaSpec { - var v1alpha1MetaSpec MetaSpec - v1alpha1MetaSpec.Crossplane = c.pV1alpha1CrossplaneConstraintsToPV1alpha1CrossplaneConstraints(source.Crossplane) - var v1alpha1DependencyList []Dependency - if source.DependsOn != nil { - v1alpha1DependencyList = make([]Dependency, len(source.DependsOn)) - for i := 0; i < len(source.DependsOn); i++ { - v1alpha1DependencyList[i] = c.v1alpha1DependencyToV1alpha1Dependency(source.DependsOn[i]) - } - } - v1alpha1MetaSpec.DependsOn = v1alpha1DependencyList - return v1alpha1MetaSpec -} func (c *GeneratedToHubConverter) v1alpha1ProviderSpecToV1ProviderSpec(source ProviderSpec) v1.ProviderSpec { var v1ProviderSpec v1.ProviderSpec v1ProviderSpec.Controller = c.v1alpha1ControllerSpecToV1ControllerSpec(source.Controller) From 32e8ea77a0b284f3b926e48290ed6da36dbee9b3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:43:04 +0000 Subject: [PATCH 017/148] Update module github.com/bufbuild/buf to v1.23.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0498a4cf2..0a83f147e 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 - github.com/bufbuild/buf v1.23.0 + github.com/bufbuild/buf v1.23.1 github.com/crossplane/crossplane-runtime v0.20.0-rc.0.0.20230622044456-2dfb8bc6bfbc github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 diff --git a/go.sum b/go.sum index 3366f737d..9688710c0 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,8 @@ github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bufbuild/buf v1.23.0 h1:QD6xCygtCVhN6qsQ4TtE2xGRK86xGkjI9lNHJ5jaj+M= -github.com/bufbuild/buf v1.23.0/go.mod h1:ERFRzJiIjAOzUSJ3vz1zoI7XfxlBnCwZEyL+NJm4pko= +github.com/bufbuild/buf v1.23.1 h1:BeMkA3+e9XTFEZPDlAI7cydFKlq24wwYiOHp8CvsRzc= +github.com/bufbuild/buf v1.23.1/go.mod h1:ERFRzJiIjAOzUSJ3vz1zoI7XfxlBnCwZEyL+NJm4pko= github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc= github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk= From 206095bb535ff1ac600e762ca7c39e581537f3a8 Mon Sep 17 00:00:00 2001 From: Bob Haddleton Date: Fri, 30 Jun 2023 21:36:33 -0500 Subject: [PATCH 018/148] Address review comments Signed-off-by: Bob Haddleton --- internal/controller/apiextensions/composite/composition_ptf.go | 2 +- internal/xfn/container_linux.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/controller/apiextensions/composite/composition_ptf.go b/internal/controller/apiextensions/composite/composition_ptf.go index 84d22e7cb..4dded326b 100644 --- a/internal/controller/apiextensions/composite/composition_ptf.go +++ b/internal/controller/apiextensions/composite/composition_ptf.go @@ -649,7 +649,7 @@ type ContainerFunctionRunnerOption func(ctx context.Context, fn *v1.ContainerFun // 2. Loads credentials from the supplied service account's image pull secrets. // 3. Loads credentials from the function's image pull secrets. // 4. Loads credentials using the GKE, EKS, or AKS credentials helper. -func WithKubernetesAuthentication(c client.Reader, namespace, serviceAccount string, registry string) ContainerFunctionRunnerOption { +func WithKubernetesAuthentication(c client.Reader, namespace, serviceAccount, registry string) ContainerFunctionRunnerOption { return func(ctx context.Context, fn *v1.ContainerFunction, r *fnv1alpha1.RunFunctionRequest) error { sa := &corev1.ServiceAccount{} diff --git a/internal/xfn/container_linux.go b/internal/xfn/container_linux.go index 2605652cc..2b083dbd2 100644 --- a/internal/xfn/container_linux.go +++ b/internal/xfn/container_linux.go @@ -98,7 +98,8 @@ func (r *ContainerRunner) RunFunction(ctx context.Context, req *v1alpha1.RunFunc bundle, then executes an OCI runtime in order to actually execute the function. */ - cmd := exec.CommandContext(ctx, os.Args[0], spark, "--cache-dir="+r.cache, "--registry="+r.registry, fmt.Sprintf("--max-stdio-bytes=%d", MaxStdioBytes)) //nolint:gosec // We're intentionally executing with variable input. + cmd := exec.CommandContext(ctx, os.Args[0], spark, "--cache-dir="+r.cache, "--registry="+r.registry, //nolint:gosec // We're intentionally executing with variable input. + fmt.Sprintf("--max-stdio-bytes=%d", MaxStdioBytes)) cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUSER | syscall.CLONE_NEWNS, UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: r.rootUID, Size: 1}}, From 495795e2809c26c324fcd5d5cc846c20369a5480 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Tue, 27 Jun 2023 15:37:48 +0200 Subject: [PATCH 019/148] tests: refactor e2e to be more idiomatic Signed-off-by: Philippe Scorsolini --- test/e2e/apiextensions_test.go | 259 ++++++------------ test/e2e/main_test.go | 4 + .../validation/composition-invalid.yaml} | 0 .../validation/composition-valid.yaml} | 0 .../validation}/prerequisites/definition.yaml | 0 .../validation}/prerequisites/provider.yaml | 0 .../prerequisites/definition.yaml | 34 --- .../prerequisites/provider.yaml | 7 - test/e2e/pkg_test.go | 163 ++++------- 9 files changed, 144 insertions(+), 323 deletions(-) rename test/e2e/manifests/apiextensions/{validation/composition-schema-invalid/composition.yaml => composition/validation/composition-invalid.yaml} (100%) rename test/e2e/manifests/apiextensions/{validation/composition-schema-valid/composition.yaml => composition/validation/composition-valid.yaml} (100%) rename test/e2e/manifests/apiextensions/{validation/composition-schema-invalid => composition/validation}/prerequisites/definition.yaml (100%) rename test/e2e/manifests/apiextensions/{validation/composition-schema-invalid => composition/validation}/prerequisites/provider.yaml (100%) delete mode 100644 test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/definition.yaml delete mode 100644 test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/provider.yaml diff --git a/test/e2e/apiextensions_test.go b/test/e2e/apiextensions_test.go index 833fe6cd0..9ad09a46d 100644 --- a/test/e2e/apiextensions_test.go +++ b/test/e2e/apiextensions_test.go @@ -34,213 +34,124 @@ import ( // extensions (i.e. Composition, XRDs, etc). const LabelAreaAPIExtensions = "apiextensions" -// TestComposition tests Crossplane's Composition functionality. -func TestComposition(t *testing.T) { - // Test that a claim using a very minimal Composition (with no patches, - // transforms, or functions) will become available when its composed - // resources do. +// TestCompositionMinimal tests Crossplane's Composition functionality, +// checking that a claim using a very minimal Composition (with no patches, +// transforms, or functions) will become available when its composed +// resources do. +func TestCompositionMinimal(t *testing.T) { manifests := "test/e2e/manifests/apiextensions/composition/minimal" - minimal := features.Table{ - { - Name: "PrerequisitesAreCreated", - Assessment: funcs.AllOf( + + environment.Test(t, + features.New("CompositionMinimal"). + WithLabel(LabelArea, LabelAreaAPIExtensions). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("PrerequisitesAreCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - ), - }, - { - Name: "XRDBecomesEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - }, - { - Name: "ClaimIsCreated", - Assessment: funcs.AllOf( + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), + )). + Assess("ClaimCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), - ), - }, - { - Name: "ClaimBecomesAvailable", - Assessment: funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available()), - }, - { - Name: "ClaimIsDeleted", - Assessment: funcs.AllOf( + funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available()), + )). + WithTeardown("ClaimIsDeleted", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), - ), - }, - { - Name: "PrerequisitesAreDeleted", - Assessment: funcs.AllOf( + )). + WithTeardown("PrerequisitesAreDeleted", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), - ), - }, - } + )). + Feature(), + ) +} - // Test that a claim using patch-and-transform Composition will become - // available when its composed resources do, and have a field derived from - // the patch. - manifests = "test/e2e/manifests/apiextensions/composition/patch-and-transform" - pandt := features.Table{ - { - Name: "PrerequisitesAreCreated", - Assessment: funcs.AllOf( +// TestCompositionPatchAndTransform tests Crossplane's Composition functionality, +// checking that a claim using patch-and-transform Composition will become +// available when its composed resources do, and have a field derived from +// the patch. +func TestCompositionPatchAndTransform(t *testing.T) { + + manifests := "test/e2e/manifests/apiextensions/composition/patch-and-transform" + environment.Test(t, + features.New("CompositionPatchAndTransform"). + WithLabel(LabelArea, LabelAreaAPIExtensions). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("PrerequisitesAreCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - ), - }, - { - Name: "XRDBecomesEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - }, - { - Name: "ClaimIsCreated", - Assessment: funcs.AllOf( + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), + )). + Assess("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), - ), - }, - { - Name: "ClaimBecomesAvailable", - Assessment: funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available()), - }, - { - Name: "ClaimHasPatchedField", - Assessment: funcs.ResourcesHaveFieldValueWithin(5*time.Minute, manifests, "claim.yaml", "status.coolerField", "I'M COOL!"), - }, - { - Name: "ClaimIsDeleted", - Assessment: funcs.AllOf( + )). + Assess("ClaimIsReadyWithinTimeout", + funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ClaimHasPatchedField", + funcs.ResourcesHaveFieldValueWithin(5*time.Minute, manifests, "claim.yaml", "status.coolerField", "I'M COOL!"), + ). + WithTeardown("ClaimIsDeleted", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), - ), - }, - { - Name: "PrerequisitesAreDeleted", - Assessment: funcs.AllOf( + )). + WithTeardown("PrerequisitesAreDeleted", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), - ), - }, - } - - setup := funcs.ReadyToTestWithin(1*time.Minute, namespace) - environment.Test(t, - minimal.Build("Minimal"). - WithLabel(LabelArea, LabelAreaAPIExtensions). - WithLabel(LabelSize, LabelSizeSmall). - Setup(setup).Feature(), - pandt.Build("PatchAndTransform"). - WithLabel(LabelArea, LabelAreaAPIExtensions). - WithLabel(LabelSize, LabelSizeSmall). - Setup(setup).Feature(), + )). + Feature(), ) -} -func TestValidation(t *testing.T) { +} - // A valid Composition should be created when validated in strict mode. - manifests := "test/e2e/manifests/apiextensions/validation/composition-schema-valid" - valid := features.Table{ - { - Name: "PrerequisitesAreCreated", - Assessment: funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - ), - }, - { - Name: "XRDBecomesEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - }, - { - Name: "ProviderIsHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/provider.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "CompositionIsCreated", - Assessment: funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "composition.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "composition.yaml"), - ), - }, - { - Name: "CompositionIsDeleted", - Assessment: funcs.AllOf( - funcs.DeleteResources(manifests, "composition.yaml"), - funcs.ResourcesDeletedWithin(30*time.Second, manifests, "composition.yaml"), - ), - }, - { - Name: "PrerequisitesAreDeleted", - Assessment: funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), - ), - }, - } +func TestCompositionValidation(t *testing.T) { + manifests := "test/e2e/manifests/apiextensions/composition/validation" - // An invalid Composition should be rejected when validated in strict mode. - manifests = "test/e2e/manifests/apiextensions/validation/composition-schema-invalid" - invalid := features.Table{ + cases := features.Table{ { - Name: "PrerequisitesAreCreated", + // A valid Composition should be created when validated in strict mode. + Name: "ValidCompositionIsAccepted", Assessment: funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), + funcs.ApplyResources(FieldManager, manifests, "composition-valid.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "composition-valid.yaml"), ), }, { - Name: "XRDBecomesEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - }, - { - Name: "ProviderIsHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/provider.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "CompositionIsCreated", - Assessment: funcs.AllOf( - funcs.ResourcesFailToApply(FieldManager, manifests, "composition.yaml"), - ), - }, - { - Name: "PrerequisitesAreDeleted", - Assessment: funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), - ), + // An invalid Composition should be rejected when validated in strict mode. + Name: "InvalidCompositionIsRejected", + Assessment: funcs.ResourcesFailToApply(FieldManager, manifests, "composition-invalid.yaml"), }, } - - // Enable our feature flag. - setup := funcs.AllOf( - funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions(helm.WithArgs("--set args={--debug,--enable-composition-webhook-schema-validation}"))...)), - funcs.ReadyToTestWithin(1*time.Minute, namespace), - ) - - // Disable our feature flag. - teardown := funcs.AllOf( - funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), - funcs.ReadyToTestWithin(1*time.Minute, namespace), - ) - environment.Test(t, - valid.Build("ValidComposition"). - WithLabel(LabelStage, LabelStageAlpha). - WithLabel(LabelArea, LabelAreaAPIExtensions). - WithLabel(LabelSize, LabelSizeSmall). - Setup(setup). - Teardown(teardown). - Feature(), - invalid.Build("InvalidComposition"). + cases.Build("CompositionValidation"). WithLabel(LabelStage, LabelStageAlpha). WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). - Setup(setup). - Teardown(teardown). + // Enable our feature flag. + WithSetup("EnableAlphaCompositionValidation", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions(helm.WithArgs("--set args={--debug,--enable-composition-webhook-schema-validation}"))...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). + WithSetup("ApplyPrerequisites", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/provider.yaml", pkgv1.Healthy(), pkgv1.Active()), + )). + WithTeardown("DeleteValidComposition", funcs.AllOf( + funcs.DeleteResources(manifests, "*-valid.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "*-valid.yaml"), + )). + WithTeardown("DeletePrerequisites", funcs.AllOf( + funcs.DeleteResources(manifests, "prerequisites/*.yaml"), + funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), + )). + // Disable our feature flag. + WithTeardown("DisableAlphaCompositionValidation", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). Feature(), ) } diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 8c3813ead..f147c97d4 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -98,6 +98,10 @@ func HelmOptions(extra ...helm.Option) []helm.Option { "--set xfn.args={--debug}", "--set xfn.image.repository="+strings.Split(imgxfn, ":")[0], "--set xfn.image.tag="+strings.Split(imgxfn, ":")[1], + + // wait for the deployment to be ready for up to 5 minutes before returning + "--wait", + "--timeout=5m", ), } return append(o, extra...) diff --git a/test/e2e/manifests/apiextensions/validation/composition-schema-invalid/composition.yaml b/test/e2e/manifests/apiextensions/composition/validation/composition-invalid.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/validation/composition-schema-invalid/composition.yaml rename to test/e2e/manifests/apiextensions/composition/validation/composition-invalid.yaml diff --git a/test/e2e/manifests/apiextensions/validation/composition-schema-valid/composition.yaml b/test/e2e/manifests/apiextensions/composition/validation/composition-valid.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/validation/composition-schema-valid/composition.yaml rename to test/e2e/manifests/apiextensions/composition/validation/composition-valid.yaml diff --git a/test/e2e/manifests/apiextensions/validation/composition-schema-invalid/prerequisites/definition.yaml b/test/e2e/manifests/apiextensions/composition/validation/prerequisites/definition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/validation/composition-schema-invalid/prerequisites/definition.yaml rename to test/e2e/manifests/apiextensions/composition/validation/prerequisites/definition.yaml diff --git a/test/e2e/manifests/apiextensions/validation/composition-schema-invalid/prerequisites/provider.yaml b/test/e2e/manifests/apiextensions/composition/validation/prerequisites/provider.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/validation/composition-schema-invalid/prerequisites/provider.yaml rename to test/e2e/manifests/apiextensions/composition/validation/prerequisites/provider.yaml diff --git a/test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/definition.yaml b/test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/definition.yaml deleted file mode 100644 index afe55de66..000000000 --- a/test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/definition.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: apiextensions.crossplane.io/v1 -kind: CompositeResourceDefinition -metadata: - name: xnopresources.nop.example.org -spec: - group: nop.example.org - names: - kind: XNopResource - plural: xnopresources - claimNames: - kind: NopResource - plural: nopresources - connectionSecretKeys: - - test - versions: - - name: v1alpha1 - served: true - referenceable: true - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - coolField: - type: string - required: - - coolField - status: - type: object - properties: - coolerField: - type: string \ No newline at end of file diff --git a/test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/provider.yaml b/test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/provider.yaml deleted file mode 100644 index 2f8d0708f..000000000 --- a/test/e2e/manifests/apiextensions/validation/composition-schema-valid/prerequisites/provider.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: pkg.crossplane.io/v1 -kind: Provider -metadata: - name: provider-nop -spec: - package: xpkg.upbound.io/crossplane-contrib/provider-nop:v0.2.0 - ignoreCrossplaneConstraints: true \ No newline at end of file diff --git a/test/e2e/pkg_test.go b/test/e2e/pkg_test.go index 4b7693b2e..e0a1f6883 100644 --- a/test/e2e/pkg_test.go +++ b/test/e2e/pkg_test.go @@ -32,140 +32,87 @@ import ( // Providers, Configurations, etc). const LabelAreaPkg = "pkg" -func TestConfiguration(t *testing.T) { - // Test that we can install a Configuration from a private repository using - // a package pull secret. +// TestConfigurationPullFromPrivateRegistry tests that a Configuration can be +// installed from a private registry using a package pull secret. +func TestConfigurationPullFromPrivateRegistry(t *testing.T) { manifests := "test/e2e/manifests/pkg/configuration/private" - private := features.Table{ - { - Name: "ConfigurationIsCreated", - Assessment: funcs.AllOf( + + environment.Test(t, + features.New("ConfigurationPullFromPrivateRegistry"). + WithLabel(LabelArea, LabelAreaPkg). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("ConfigurationCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "*.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "*.yaml"), - ), - }, - { - Name: "ConfigurationIsHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "ConfigurationIsDeleted", - Assessment: funcs.AllOf( + )). + Assess("ConfigurationHealthyBeforeTimeout", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active())). + WithTeardown("DeleteConfiguration", funcs.AllOf( funcs.DeleteResources(manifests, "*.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "*.yaml"), - ), - }, - } + )).Feature(), + ) +} - manifests = "test/e2e/manifests/pkg/configuration/dependency" - dependency := features.Table{ - { - Name: "ConfigurationIsCreated", - Assessment: funcs.AllOf( +// TestConfigurationWithDependency tests that a Configuration with a dependency +// on a Provider will become healthy when the Provider becomes healthy. +func TestConfigurationWithDependency(t *testing.T) { + manifests := "test/e2e/manifests/pkg/configuration/dependency" + + environment.Test(t, + features.New("ConfigurationWithDependency"). + WithLabel(LabelArea, LabelAreaPkg). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("ReadyConfiguration", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "configuration.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "configuration.yaml"), - ), - }, - { - Name: "ConfigurationIsHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "ProviderIsHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-dependency.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "ConfigurationIsDeleted", - Assessment: funcs.AllOf( + )). + Assess("ConfigurationHealthyBeforeTimeout", + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active())). + Assess("RequiredProviderHealthyBeforeTimeout", + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-dependency.yaml", pkgv1.Healthy(), pkgv1.Active())). + Teardown(funcs.AllOf( funcs.DeleteResources(manifests, "configuration.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "configuration.yaml"), - ), - }, - { - // Dependencies are not automatically deleted. - Name: "ProviderIsDeleted", - Assessment: funcs.AllOf( funcs.DeleteResources(manifests, "provider-dependency.yaml"), + // Dependencies are not automatically deleted. funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "provider-dependency.yaml"), - ), - }, - } - - setup := funcs.ReadyToTestWithin(1*time.Minute, namespace) - environment.Test(t, - private.Build("PullFromPrivateRegistry"). - WithLabel(LabelArea, LabelAreaPkg). - WithLabel(LabelSize, LabelSizeSmall). - Setup(setup).Feature(), - dependency.Build("WithDependency"). - WithLabel(LabelArea, LabelAreaPkg). - WithLabel(LabelSize, LabelSizeSmall). - Setup(setup).Feature(), + )).Feature(), ) } -func TestProvider(t *testing.T) { +func TestProviderUpgrade(t *testing.T) { // Test that we can upgrade a provider to a new version, even when a managed // resource has been created. manifests := "test/e2e/manifests/pkg/provider" - upgrade := features.Table{ - { - Name: "ProviderIsInstalled", - Assessment: funcs.AllOf( + + environment.Test(t, + features.New("ProviderUpgrade"). + WithLabel(LabelArea, LabelAreaPkg). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("ReadyInitialProvider", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "provider-initial.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "provider-initial.yaml"), - ), - }, - { - Name: "ProviderBecomesHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-initial.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "ManagedResourceIsCreated", - Assessment: funcs.AllOf( + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-initial.yaml", pkgv1.Healthy(), pkgv1.Active()), + )). + WithSetup("ReadyInitialManagedResource", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "mr-initial.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "mr-initial.yaml"), - ), - }, - { - Name: "ProviderIsUpgraded", - Assessment: funcs.ApplyResources(FieldManager, manifests, "provider-upgrade.yaml"), - }, - { - Name: "UpgradedProviderBecomesHealthy", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-upgrade.yaml", pkgv1.Healthy(), pkgv1.Active()), - }, - { - Name: "ManagedResourceIsUpdated", - Assessment: funcs.AllOf( + )). + Assess("UpgradeProvider", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "provider-upgrade.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-upgrade.yaml", pkgv1.Healthy(), pkgv1.Active()), + )). + Assess("UpgradeManagedResource", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "mr-upgrade.yaml"), - ), - }, - { - Name: "ManagedResourceBecomesAvailable", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "mr.yaml", xpv1.Available()), - }, - { - Name: "ManagedResourceIsDeleted", - Assessment: funcs.AllOf( + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "mr.yaml", xpv1.Available()), + )). + WithTeardown("DeletedUpgradedManagedResource", funcs.AllOf( funcs.DeleteResources(manifests, "mr-upgrade.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "mr-upgrade.yaml"), - ), - }, - { - Name: "ProviderIsDeleted", - Assessment: funcs.AllOf( + )). + WithTeardown("DeletedUpgradedProvider", funcs.AllOf( funcs.DeleteResources(manifests, "provider-upgrade.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "provider-upgrade.yaml"), - ), - }, - } - - setup := funcs.ReadyToTestWithin(1*time.Minute, namespace) - environment.Test(t, - upgrade.Build("Upgrade"). - WithLabel(LabelArea, LabelAreaPkg). - WithLabel(LabelSize, LabelSizeSmall). - Setup(setup).Feature(), + )).Feature(), ) } From 80cab49e4705df8f3712dce30962b04b12430af4 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Tue, 27 Jun 2023 16:22:20 +0200 Subject: [PATCH 020/148] tests: set helm timeout and wait through options Signed-off-by: Philippe Scorsolini --- test/e2e/main_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index f147c97d4..32547d4b1 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -89,6 +89,9 @@ func HelmOptions(extra ...helm.Option) []helm.Option { helm.WithName(helmReleaseName), helm.WithNamespace(namespace), helm.WithChart(helmChartDir), + // wait for the deployment to be ready for up to 5 minutes before returning + helm.WithWait(), + helm.WithTimeout("5m"), helm.WithArgs( // Run with debug logging to ensure all log statements are run. "--set args={--debug}", @@ -98,10 +101,6 @@ func HelmOptions(extra ...helm.Option) []helm.Option { "--set xfn.args={--debug}", "--set xfn.image.repository="+strings.Split(imgxfn, ":")[0], "--set xfn.image.tag="+strings.Split(imgxfn, ":")[1], - - // wait for the deployment to be ready for up to 5 minutes before returning - "--wait", - "--timeout=5m", ), } return append(o, extra...) From 2f5bdb66074aca709911ab7766a7bd0a6a078551 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 28 Jun 2023 09:47:19 +0200 Subject: [PATCH 021/148] tests: refactor lifecycle test Signed-off-by: Philippe Scorsolini --- test/e2e/install_test.go | 230 ++++++------------ .../manifests/lifecycle/uninstall/claim.yaml | 10 - .../uninstall/prerequisites/composition.yaml | 22 -- .../uninstall/prerequisites/definition.yaml | 29 --- .../uninstall/prerequisites/provider.yaml | 7 - 5 files changed, 73 insertions(+), 225 deletions(-) delete mode 100644 test/e2e/manifests/lifecycle/uninstall/claim.yaml delete mode 100644 test/e2e/manifests/lifecycle/uninstall/prerequisites/composition.yaml delete mode 100644 test/e2e/manifests/lifecycle/uninstall/prerequisites/definition.yaml delete mode 100644 test/e2e/manifests/lifecycle/uninstall/prerequisites/provider.yaml diff --git a/test/e2e/install_test.go b/test/e2e/install_test.go index fb00ff653..4cee5ae5b 100644 --- a/test/e2e/install_test.go +++ b/test/e2e/install_test.go @@ -36,108 +36,72 @@ import ( // Crossplane's lifecycle (installing, upgrading, etc). const LabelAreaLifecycle = "lifecycle" -// TestCrossplane tests installing, uninstalling, and upgrading Crossplane. -func TestCrossplane(t *testing.T) { - // We install Crossplane as part of setting up the test environment, so - // we're really only validating the installation here. - install := features.Table{ - { - Name: "CoreDeploymentBecomesAvailable", - Assessment: funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane"), - }, - { - Name: "RBACManagerDeploymentBecomesAvailable", - Assessment: funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane-rbac-manager"), - }, - { - Name: "CoreCRDsBecomeEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, crdsDir, "*.yaml", funcs.CRDInitialNamesAccepted()), - }, - } +// TestCrossplaneLifecycle tests two features expecting them to be run in order: +// - Uninstall: Test that it's possible to cleanly uninstall Crossplane, even +// after having created and deleted a claim. +// - Upgrade: Test that it's possible to upgrade Crossplane from the most recent +// stable Helm chart to the one we're testing, even when a claim exists. This +// expects the Uninstall feature to have been run first. +// +// Note: First time Installation is tested as part of the environment setup, +// if not disabled explicitly. +func TestCrossplaneLifecycle(t *testing.T) { - // Test that it's possible to cleanly uninstall Crossplane, even after - // having created and deleted a claim. - manifests := "test/e2e/manifests/lifecycle/uninstall" - uninstall := features.Table{ - { - Name: "ClaimPrerequisitesAreCreated", - Assessment: funcs.AllOf( + manifests := "test/e2e/manifests/lifecycle/upgrade" + environment.Test(t, + // Test that it's possible to cleanly uninstall Crossplane, even after + // having created and deleted a claim. + features.New("Uninstall"). + WithLabel(LabelArea, LabelAreaLifecycle). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("CreatePrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - ), - }, - { - Name: "XRDBecomesEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - }, - { - Name: "ClaimIsCreated", - Assessment: funcs.AllOf( + )). + WithSetup("XRDBecomesEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + WithSetup("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), - ), - }, - { - Name: "ClaimBecomesAvailable", - Assessment: funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available()), - }, - { - Name: "ClaimIsDeleted", - Assessment: funcs.AllOf( + )). + WithSetup("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), - ), - }, - { - Name: "PrerequisitesAreDeleted", - Assessment: funcs.AllOf( + )). + Assess("DeletePrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), - ), - }, - { - Name: "CrossplaneIsUninstalled", - Assessment: funcs.AsFeaturesFunc(funcs.HelmUninstall( - helm.WithName(helmReleaseName), - helm.WithNamespace(namespace), - )), - }, - // Uninstalling the Crossplane Helm chart doesn't remove its CRDs. We - // want to make sure they can be deleted cleanly. If they can't, it's a - // sign something they define might have stuck around. - { - Name: "CoreCRDsAreDeleted", - Assessment: funcs.AllOf( + funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "prerequisites/*.yaml"), + )). + Assess("UninstallCrossplane", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUninstall(helm.WithName(helmReleaseName), helm.WithNamespace(namespace))), + )). + // Uninstalling the Crossplane Helm chart doesn't remove its CRDs. We + // want to make sure they can be deleted cleanly. If they can't, it's a + // sign something they define might have stuck around. + WithTeardown("DeleteCrossplaneCRDs", funcs.AllOf( funcs.DeleteResources(crdsDir, "*.yaml"), funcs.ResourcesDeletedWithin(3*time.Minute, crdsDir, "*.yaml"), - ), - }, - // Uninstalling the Crossplane Helm chart doesn't remove the namespace - // it was installed to either. We want to make sure it can be deleted - // cleanly. - { - Name: "CrossplaneNamespaceIsDeleted", - Assessment: funcs.AllOf( + )). + // Uninstalling the Crossplane Helm chart doesn't remove the namespace + // it was installed to either. We want to make sure it can be deleted + // cleanly. + WithTeardown("DeleteCrossplaneNamespace", funcs.AllOf( funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(namespace)), funcs.ResourceDeletedWithin(3*time.Minute, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}), - ), - }, - } - - // Test that it's possible to upgrade from the most recent stable Crossplane - // Helm chart to the one we're testing, even when a claim exists. - manifests = "test/e2e/manifests/lifecycle/upgrade" - upgrade := features.Table{ - { - Name: "CrossplaneNamespaceIsCreated", - Assessment: funcs.AllOf( + )). + Feature(), + features.New("Upgrade"). + WithLabel(LabelArea, LabelAreaLifecycle). + WithLabel(LabelSize, LabelSizeSmall). + WithSetup("CrossplaneIsUninstalled", funcs.AllOf( + // We expect Crossplane to have been uninstalled first + funcs.ResourceDeletedWithin(1*time.Minute, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}), + )). + WithSetup("CreateCrossplane", funcs.AllOf( funcs.AsFeaturesFunc(envfuncs.CreateNamespace(namespace)), funcs.ResourceCreatedWithin(1*time.Minute, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}), - ), - }, - { - Name: "CrossplaneStableIsInstalled", - Assessment: funcs.AllOf( + )). + WithSetup("InstallStableCrossplane", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmRepo( helm.WithArgs("add"), helm.WithArgs("crossplane-stable"), @@ -148,82 +112,34 @@ func TestCrossplane(t *testing.T) { helm.WithName(helmReleaseName), helm.WithChart("crossplane-stable/crossplane"), )), - ), - }, - { - Name: "CrossplaneStableIsRunning", - Assessment: funcs.ReadyToTestWithin(1*time.Minute, namespace), - }, - { - Name: "ClaimPrerequisitesAreCreated", - Assessment: funcs.AllOf( + funcs.ReadyToTestWithin(1*time.Minute, namespace))). + WithSetup("CreateClaimPrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - ), - }, - { - Name: "XRDBecomesEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - }, - { - Name: "ClaimIsCreated", - Assessment: funcs.AllOf( + )). + WithSetup("XRDBecomesEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + WithSetup("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), - ), - }, - { - Name: "ClaimBecomesAvailable", - Assessment: funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available()), - }, - { - Name: "CrossplaneIsUpgraded", - Assessment: funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), - }, - { - Name: "CoreDeploymentBecomesAvailable", - Assessment: funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane"), - }, - { - Name: "RBACManagerDeploymentBecomesAvailable", - Assessment: funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane-rbac-manager"), - }, - { - Name: "CoreCRDsBecomeEstablished", - Assessment: funcs.ResourcesHaveConditionWithin(1*time.Minute, crdsDir, "*.yaml", funcs.CRDInitialNamesAccepted()), - }, - { - Name: "ClaimStillAvailable", - Assessment: funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available()), - }, - { - Name: "ClaimIsDeleted", - Assessment: funcs.AllOf( + )). + WithSetup("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("UpgradeCrossplane", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). + Assess("CoreDeploymentBecomesAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane")). + Assess("RBACManagerDeploymentBecomesAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane-rbac-manager")). + Assess("CoreCRDsBecomeEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, crdsDir, "*.yaml", funcs.CRDInitialNamesAccepted())). + Assess("ClaimStillAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ClaimIsStillAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), - ), - }, - { - Name: "ClaimPrerequisitesAreDeleted", - Assessment: funcs.AllOf( + )). + WithTeardown("DeletePrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), - ), - }, - } - - environment.Test(t, - install.Build("Install"). - WithLabel(LabelArea, LabelAreaLifecycle). - WithLabel(LabelSize, LabelSizeSmall). - Feature(), - uninstall.Build("Uninstall"). - WithLabel(LabelArea, LabelAreaLifecycle). - WithLabel(LabelSize, LabelSizeLarge). - Feature(), - upgrade.Build("Upgrade"). - WithLabel(LabelArea, LabelAreaLifecycle). - WithLabel(LabelSize, LabelSizeLarge). + funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "prerequisites/*.yaml"), + )). Feature(), ) } diff --git a/test/e2e/manifests/lifecycle/uninstall/claim.yaml b/test/e2e/manifests/lifecycle/uninstall/claim.yaml deleted file mode 100644 index be6360adf..000000000 --- a/test/e2e/manifests/lifecycle/uninstall/claim.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: nop.example.org/v1alpha1 -kind: NopResource -metadata: - namespace: default - name: lifecycle-uninstall -spec: - coolField: "I'm cool!" - # This is necessary to ensure the claim's MRs are actually gone before we - # delete the Provider - https://github.com/crossplane/crossplane/issues/4251 - compositeDeletePolicy: Foreground diff --git a/test/e2e/manifests/lifecycle/uninstall/prerequisites/composition.yaml b/test/e2e/manifests/lifecycle/uninstall/prerequisites/composition.yaml deleted file mode 100644 index 850f430e6..000000000 --- a/test/e2e/manifests/lifecycle/uninstall/prerequisites/composition.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: apiextensions.crossplane.io/v1 -kind: Composition -metadata: - name: xnopresources.nop.example.org -spec: - compositeTypeRef: - apiVersion: nop.example.org/v1alpha1 - kind: XNopResource - resources: - - name: nop-resource-1 - base: - apiVersion: nop.crossplane.io/v1alpha1 - kind: NopResource - spec: - forProvider: - conditionAfter: - - conditionType: Ready - conditionStatus: "False" - time: 0s - - conditionType: Ready - conditionStatus: "True" - time: 10s diff --git a/test/e2e/manifests/lifecycle/uninstall/prerequisites/definition.yaml b/test/e2e/manifests/lifecycle/uninstall/prerequisites/definition.yaml deleted file mode 100644 index bf70cb798..000000000 --- a/test/e2e/manifests/lifecycle/uninstall/prerequisites/definition.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: apiextensions.crossplane.io/v1 -kind: CompositeResourceDefinition -metadata: - name: xnopresources.nop.example.org -spec: - group: nop.example.org - names: - kind: XNopResource - plural: xnopresources - claimNames: - kind: NopResource - plural: nopresources - connectionSecretKeys: - - test - versions: - - name: v1alpha1 - served: true - referenceable: true - schema: - openAPIV3Schema: - type: object - properties: - spec: - type: object - properties: - coolField: - type: string - required: - - coolField \ No newline at end of file diff --git a/test/e2e/manifests/lifecycle/uninstall/prerequisites/provider.yaml b/test/e2e/manifests/lifecycle/uninstall/prerequisites/provider.yaml deleted file mode 100644 index 2f8d0708f..000000000 --- a/test/e2e/manifests/lifecycle/uninstall/prerequisites/provider.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: pkg.crossplane.io/v1 -kind: Provider -metadata: - name: provider-nop -spec: - package: xpkg.upbound.io/crossplane-contrib/provider-nop:v0.2.0 - ignoreCrossplaneConstraints: true \ No newline at end of file From 9ee1b298066c2b8e166d794f4efb951933929a1e Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 28 Jun 2023 12:48:03 +0200 Subject: [PATCH 022/148] tests: use reflection to get Kind if empty not Signed-off-by: Philippe Scorsolini --- test/e2e/funcs/feature.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index 759b174bf..1a942f05d 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -22,6 +22,7 @@ import ( "io/fs" "os" "path/filepath" + "reflect" "strings" "testing" "time" @@ -404,6 +405,9 @@ func asUnstructured(o runtime.Object) *unstructured.Unstructured { // namespace. func identifier(o k8s.Object) string { k := o.GetObjectKind().GroupVersionKind().Kind + if k == "" { + k = reflect.TypeOf(o).Elem().Name() + } if o.GetNamespace() == "" { return fmt.Sprintf("%s %s", k, o.GetName()) } From 9178fa1256e722546890cf0ef167b86c9ff0e08b Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 28 Jun 2023 12:49:00 +0200 Subject: [PATCH 023/148] tests: minor refactor Upgrade test Signed-off-by: Philippe Scorsolini --- test/e2e/install_test.go | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/test/e2e/install_test.go b/test/e2e/install_test.go index 4cee5ae5b..a3ba44b21 100644 --- a/test/e2e/install_test.go +++ b/test/e2e/install_test.go @@ -46,7 +46,6 @@ const LabelAreaLifecycle = "lifecycle" // Note: First time Installation is tested as part of the environment setup, // if not disabled explicitly. func TestCrossplaneLifecycle(t *testing.T) { - manifests := "test/e2e/manifests/lifecycle/upgrade" environment.Test(t, // Test that it's possible to cleanly uninstall Crossplane, even after @@ -93,15 +92,12 @@ func TestCrossplaneLifecycle(t *testing.T) { features.New("Upgrade"). WithLabel(LabelArea, LabelAreaLifecycle). WithLabel(LabelSize, LabelSizeSmall). - WithSetup("CrossplaneIsUninstalled", funcs.AllOf( - // We expect Crossplane to have been uninstalled first + // We expect Crossplane to have been uninstalled first + Assess("CrossplaneIsNotInstalled", funcs.AllOf( funcs.ResourceDeletedWithin(1*time.Minute, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}), + funcs.ResourcesDeletedWithin(3*time.Minute, crdsDir, "*.yaml"), )). - WithSetup("CreateCrossplane", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.CreateNamespace(namespace)), - funcs.ResourceCreatedWithin(1*time.Minute, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}), - )). - WithSetup("InstallStableCrossplane", funcs.AllOf( + Assess("InstallStableCrossplane", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmRepo( helm.WithArgs("add"), helm.WithArgs("crossplane-stable"), @@ -111,18 +107,19 @@ func TestCrossplaneLifecycle(t *testing.T) { helm.WithNamespace(namespace), helm.WithName(helmReleaseName), helm.WithChart("crossplane-stable/crossplane"), + helm.WithArgs("--create-namespace"), )), funcs.ReadyToTestWithin(1*time.Minute, namespace))). - WithSetup("CreateClaimPrerequisites", funcs.AllOf( + Assess("CreateClaimPrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), )). - WithSetup("XRDBecomesEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). - WithSetup("CreateClaim", funcs.AllOf( + Assess("XRDBecomesEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + Assess("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - WithSetup("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("UpgradeCrossplane", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), funcs.ReadyToTestWithin(1*time.Minute, namespace), From dff680ccd580b6ed73125fefa3c07dbccb4ff6ed Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 28 Jun 2023 14:17:26 +0200 Subject: [PATCH 024/148] tests: allow running e2es against existing installation Signed-off-by: Philippe Scorsolini --- Makefile | 6 ++-- test/e2e/README.md | 12 +++++-- test/e2e/apiextensions_test.go | 1 + test/e2e/install_test.go | 5 +-- test/e2e/main_test.go | 59 ++++++++++++++++++++++++++++------ 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 6e6acb39b..f31b938b1 100644 --- a/Makefile +++ b/Makefile @@ -120,7 +120,7 @@ e2e-tag-images: @$(INFO) Tagging E2E test images @docker tag $(BUILD_REGISTRY)/$(PROJECT_NAME)-$(TARGETARCH) crossplane-e2e/$(PROJECT_NAME):latest || $(FAIL) @docker tag $(BUILD_REGISTRY)/xfn-$(TARGETARCH) crossplane-e2e/xfn:latest || $(FAIL) - @$(OK) Tagged E2E test images + @$(OK) Tagged E2E test images crossplane-e2e/$(PROJECT_NAME):latest crossplane-e2e/xfn:latest # NOTE(negz): There's already a go.test.integration target, but it's weird. # This relies on make build building the e2e binary. @@ -130,7 +130,7 @@ E2E_TEST_FLAGS ?= # https://github.com/kubernetes-sigs/e2e-framework/issues/282 E2E_PATH = $(WORK_DIR)/e2e -e2e-run-tests: $(KIND) $(HELM3) +e2e-run-tests: @$(INFO) Run E2E tests @mkdir -p $(E2E_PATH) @ln -sf $(KIND) $(E2E_PATH)/kind @@ -140,7 +140,7 @@ e2e-run-tests: $(KIND) $(HELM3) e2e.init: build e2e-tag-images -e2e.run: e2e-run-tests +e2e.run: $(KIND) $(HELM3) e2e-run-tests # Update the submodules, such as the common build scripts. submodules: diff --git a/test/e2e/README.md b/test/e2e/README.md index fa2712fb0..c66d526b7 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -38,7 +38,7 @@ E2E_TEST_FLAGS="-test.run ^TestConfiguration" make e2e E2E_TEST_FLAGS="-labels area=apiextensions" make e2e # To test a specific feature, use the feature flag -E2E_TEST_FLAGS="-feature=Install" make e2e +E2E_TEST_FLAGS="-feature=ConfigurationWithDependency" make e2e # Stop immediately on first test failure, and leave the kind cluster to debug. E2E_TEST_FLAGS="-test.v -test.failfast -destroy-kind-cluster=false" @@ -46,6 +46,14 @@ E2E_TEST_FLAGS="-test.v -test.failfast -destroy-kind-cluster=false" # Use an existing Kubernetes cluster. Note that the E2E tests can't deploy your # local build of Crossplane in this scenario, so you'll have to do it yourself. E2E_TEST_FLAGS="-create-kind-cluster=false -destroy-kind-cluster=false -kubeconfig=$HOME/.kube/config" + +# Run the CrossplaneUpgrade feature, against an existing kind cluster named "kind" (or creating it if it doesn't exist), +# without installing Crossplane first, as the feature expects the cluster to be empty, but still loading the images to +# it. Setting the tests to fail fast and not destroying the cluster afterward in order to allow debugging it. +E2E_TEST_FLAGS="-test.v -v 4 -test.failfast -destroy-kind-cluster=false -kind-cluster-name=kind -install-crossplane=false -feature=CrossplaneUpgrade" make e2e + +# Run the all tests not installing or upgrading Crossplane against the currently selected cluster where Crossplane has already been installed. +E2E_TEST_FLAGS="-test.v -v 4 -test.failfast -kubeconfig=$HOME/.kube/config -skip-labels install-crossplane=true -create-kind-cluster=false -install-crossplane=false" make go.build e2e-run-tests``` ``` ## Test Parallelism @@ -122,4 +130,4 @@ Refer to the [E2E one-pager] for more context. [CI GitHub workflow]: ../../.github/workflows/ci.yml [`testing`]: https://pkg.go.dev/testing [`e2e-framework`]: https://pkg.go.dev/sigs.k8s.io/e2e-framework -[E2e one-pager]: ../../design/one-pager-e2e-tests.md \ No newline at end of file +[E2e one-pager]: ../../design/one-pager-e2e-tests.md diff --git a/test/e2e/apiextensions_test.go b/test/e2e/apiextensions_test.go index 9ad09a46d..dfe6a67a8 100644 --- a/test/e2e/apiextensions_test.go +++ b/test/e2e/apiextensions_test.go @@ -128,6 +128,7 @@ func TestCompositionValidation(t *testing.T) { WithLabel(LabelStage, LabelStageAlpha). WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). + WithLabel(LabelInstallCrossplane, LabelInstallCrossplaneTrue). // Enable our feature flag. WithSetup("EnableAlphaCompositionValidation", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions(helm.WithArgs("--set args={--debug,--enable-composition-webhook-schema-validation}"))...)), diff --git a/test/e2e/install_test.go b/test/e2e/install_test.go index a3ba44b21..fc768e5db 100644 --- a/test/e2e/install_test.go +++ b/test/e2e/install_test.go @@ -50,9 +50,10 @@ func TestCrossplaneLifecycle(t *testing.T) { environment.Test(t, // Test that it's possible to cleanly uninstall Crossplane, even after // having created and deleted a claim. - features.New("Uninstall"). + features.New("CrossplaneUninstall"). WithLabel(LabelArea, LabelAreaLifecycle). WithLabel(LabelSize, LabelSizeSmall). + WithLabel(LabelInstallCrossplane, LabelInstallCrossplaneTrue). WithSetup("CreatePrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), @@ -89,7 +90,7 @@ func TestCrossplaneLifecycle(t *testing.T) { funcs.ResourceDeletedWithin(3*time.Minute, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}), )). Feature(), - features.New("Upgrade"). + features.New("CrossplaneUpgrade"). WithLabel(LabelArea, LabelAreaLifecycle). WithLabel(LabelSize, LabelSizeSmall). // We expect Crossplane to have been uninstalled first diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 32547d4b1..a8ea80d8b 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -17,6 +17,7 @@ limitations under the License. package e2e import ( + "context" "flag" "os" "strings" @@ -24,6 +25,7 @@ import ( "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/e2e-framework/klient/conf" "sigs.k8s.io/e2e-framework/pkg/env" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" @@ -37,6 +39,14 @@ import ( // Features within an area may be split across different test functions. const LabelArea = "area" +// LabelInstallCrossplane is used to mark tests that are going to install +// Crossplane. +const LabelInstallCrossplane = "install-crossplane" + +// LabelInstallCrossplaneTrue is used to mark tests that are going to install +// or upgrade Crossplane installation. +const LabelInstallCrossplaneTrue = "true" + // LabelStage represents the 'stage' of a feature - alpha, beta, etc. Generally // available features have no stage label. const LabelStage = "stage" @@ -115,32 +125,61 @@ func TestMain(m *testing.M) { // https://github.com/kubernetes-sigs/e2e-framework/issues/270 log.SetLogger(klog.NewKlogr()) - create := flag.Bool("create-kind-cluster", true, "create a kind cluster (and deploy Crossplane) before running tests") + kindClusterName := flag.String("kind-cluster-name", "", "name of the kind cluster to use") + create := flag.Bool("create-kind-cluster", true, "create a kind cluster (and deploy Crossplane) before running tests, if the cluster does not already exist with the same name") destroy := flag.Bool("destroy-kind-cluster", true, "destroy the kind cluster when tests complete") - - clusterName := envconf.RandomName("crossplane-e2e", 32) - environment, _ = env.NewFromFlags() + install := flag.Bool("install-crossplane", true, "install Crossplane before running tests") + load := flag.Bool("load-images-kind-cluster", true, "load Crossplane images into the kind cluster before running tests") var setup []env.Func var finish []env.Func - if *create { + cfg, _ := envconf.NewFromFlags() + + clusterName := envconf.RandomName("crossplane-e2e", 32) + if *kindClusterName != "" { + clusterName = *kindClusterName + } + + // we want to create the cluster if it doesn't exist, but only if we're + isKindCluster := *create || *kindClusterName != "" + if isKindCluster { setup = []env.Func{ envfuncs.CreateKindCluster(clusterName), + } + } else { + cfg.WithKubeconfigFile(conf.ResolveKubeConfigFile()) + setup = []env.Func{ + func(ctx context.Context, config *envconf.Config) (context.Context, error) { + return ctx, nil + }, + } + } + environment = env.NewWithConfig(cfg) + + if *load && isKindCluster { + setup = append(setup, envfuncs.LoadDockerImageToCluster(clusterName, imgcore), envfuncs.LoadDockerImageToCluster(clusterName, imgxfn), + ) + } + + // We want to destroy the cluster if we created it, but only if we created it, + // otherwise the random name will be meaningless. + if *destroy && isKindCluster { + finish = []env.Func{envfuncs.DestroyKindCluster(clusterName)} + } + + if *install { + setup = append(setup, envfuncs.CreateNamespace(namespace), funcs.HelmInstall(HelmOptions()...), - } + ) } // We always want to add our types to the scheme. setup = append(setup, funcs.AddCrossplaneTypesToScheme()) - if *destroy { - finish = []env.Func{envfuncs.DestroyKindCluster(clusterName)} - } - environment.Setup(setup...) environment.Finish(finish...) os.Exit(environment.Run(m)) From ff39a1eaf722340fdd8f2c854dcf2086a967b1c6 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 29 Jun 2023 19:23:29 +0200 Subject: [PATCH 025/148] docs: update e2e guidelines Signed-off-by: Philippe Scorsolini --- test/e2e/README.md | 90 ++++++++++++++++++++++++++++++++-- test/e2e/apiextensions_test.go | 8 +-- test/e2e/install_test.go | 20 ++++---- test/e2e/pkg_test.go | 24 ++++----- 4 files changed, 114 insertions(+), 28 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index c66d526b7..17816b06e 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -74,10 +74,94 @@ uses a matrix strategy to invoke each area as its own job, running in parallel. > We're still learning what the best way to arrange E2E tests is. It's okay for > this pattern to change if it's not working well, but please discuss first! -Each feature under test consists of: +We try to follow this pattern when adding a new test: + +1. Define a single feature per Test function, if possible. +1. Setup a directory of plain YAML manifests per test - i.e. test fixtures - at + `e2e/manifests//`, usually with a `prerequisites` sub-folder + containing resources to be deployed at setup phase and cleaned up during the + teardown. Try to avoid reusing other feature's fixtures, as this would introduce + hidden dependencies between tests. +1. Try reusing existing helpers as much as possible, see package + `github.com/crossplane/crossplane/test/e2e/funcs`, or add new ones there if + needed. +1. Prefer using the Fluent APIs to define features + (`features.New(...).WithSetup(...).Assess(...).WithTeardown(...).Feature()`). + 1. `features.Table` should be used only to define multiple self-contained + assessments to be run sequentially, but without assuming any ordering among + them, similarly to the usual table driven style we adopt for unit testing. +1. Prefer the usage of `WithSetup` and `WithTeardown` to their unnamed + counterparts (`Setup` and `Teardown`) to define the setup and teardown phases of + a feature, as they allow to provide a description. +1. Use short but explicative `CamelCase` sentences as descriptions for + everything used to define the name of tests/subtests, e.g. + `features.New("CrossplaneUpgrade", ...)` `WithSetup("InstallProviderNop", + ...)`, `Assess("ProviderNopIsInstalled", ...)`, + `WithTeardown("UninstallProviderNop", ...)`. +1. Use the `Setup` and `Teardown` phases to define respectively actions that are + not strictly part of the feature being tested, but are needed to make it + work, and actions that are needed to clean up the environment after the test + has run. +1. Use the `Asses` steps to define the steps required to exercise the actual + feature at hand. +1. Use `Asses` steps to define both conditions that should hold and actions that + should be performed. In the former case use active descriptions, e.g. + `InstallProviderNop`, while in the latter use passive descriptions, e.g. + `ProviderNopIsInstalled`. +1. Try to group actions and the checks of what you have done `Assess` step in a + single step with an active description if possible, to avoid having twice the + steps and making it explicit that we are checking the action executed by the + previous function. e.g. `"UpgradeProvider"` should both upgrade the provider + and check that it becomes healthy within a reasonable time. +1. Avoid using the available context to pass data between steps, as it makes it + harder to understand the flow of the test and could lead to data races if not + handled properly. +1. Keep in mind that all `Setup` and `Teardown` steps, wherever are defined are + always going to be executed respectively before and after all the `Assess` + steps defined, so you can define `Teardowns` immediately after the step that defined the + resource to be deleted as a sort of `defer` statement. Same applies to `Setup` + steps which could actually be located immediately before the step requiring + them. But be careful with this, as a non-linear narrative is going to be easier + to follow, so if possible stick to all Setups at the beginning and all Teardowns + at the end of the feature. +1. Features can be assigned labels, to allow dicing and slicing the test suite, + see below for more details about available labels, but overall try to define + all the labels that could be useful to select the test in the future and make + sure it's actually being selected when run in CI. + +Here an example of a test following the above guidelines: + +```go +package e2e + +// ... + +// TestSomeFeature ... +func TestSomeFeature(t *testing.T) { + manifests := "test/e2e/manifests/pkg/some-area/some-feature" + namespace := "some-namespace" + // ... other variables or constants ... + + environment.Test(t, + features.New("ConfigurationWithDependency"). + WithLabel(LabelArea, ...). + WithLabel(LabelSize, ...). + // ... + WithSetup("ReadyPrerequisites", ... ). + // ... other setup steps ... + Assess("DoSomething", ... ). + Assess("SomethingElseIsInSomeState", ... ). + // ... other assess steps ... + WithTeardown("DeleteCreatedResources", ...). + // ... other teardown steps ... + Feature(), + ) +} + +// ... +``` -1. A directory of manifests - i.e. test fixtures. -1. A `features.Table` of assessment steps. +### Features' Labels Features are grouped into broad feature areas - e.g. `TestComposition` in `composition_test.go`. Features pertaining to Composition should be added to diff --git a/test/e2e/apiextensions_test.go b/test/e2e/apiextensions_test.go index dfe6a67a8..28d564535 100644 --- a/test/e2e/apiextensions_test.go +++ b/test/e2e/apiextensions_test.go @@ -78,7 +78,7 @@ func TestCompositionPatchAndTransform(t *testing.T) { features.New("CompositionPatchAndTransform"). WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). - WithSetup("PrerequisitesAreCreated", funcs.AllOf( + WithSetup("CreatePrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), @@ -87,16 +87,16 @@ func TestCompositionPatchAndTransform(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - Assess("ClaimIsReadyWithinTimeout", + Assess("ClaimIsReady", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("ClaimHasPatchedField", funcs.ResourcesHaveFieldValueWithin(5*time.Minute, manifests, "claim.yaml", "status.coolerField", "I'M COOL!"), ). - WithTeardown("ClaimIsDeleted", funcs.AllOf( + WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - WithTeardown("PrerequisitesAreDeleted", funcs.AllOf( + WithTeardown("DeleteAllPrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), )). diff --git a/test/e2e/install_test.go b/test/e2e/install_test.go index fc768e5db..fe2bbe977 100644 --- a/test/e2e/install_test.go +++ b/test/e2e/install_test.go @@ -58,17 +58,17 @@ func TestCrossplaneLifecycle(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), )). - WithSetup("XRDBecomesEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + WithSetup("XRDAreEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). WithSetup("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - WithSetup("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + WithSetup("ClaimIsAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - Assess("DeletePrerequisites", funcs.AllOf( + Assess("DeleteAllPrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "prerequisites/*.yaml"), )). @@ -115,26 +115,26 @@ func TestCrossplaneLifecycle(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), )). - Assess("XRDBecomesEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + Assess("XRDIsEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). Assess("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ClaimIsAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("UpgradeCrossplane", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), funcs.ReadyToTestWithin(1*time.Minute, namespace), )). - Assess("CoreDeploymentBecomesAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane")). - Assess("RBACManagerDeploymentBecomesAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane-rbac-manager")). - Assess("CoreCRDsBecomeEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, crdsDir, "*.yaml", funcs.CRDInitialNamesAccepted())). - Assess("ClaimStillAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("CoreDeploymentIsAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane")). + Assess("RBACManagerDeploymentIsAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane-rbac-manager")). + Assess("CoreCRDsAreEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, crdsDir, "*.yaml", funcs.CRDInitialNamesAccepted())). + Assess("ClaimAreAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("ClaimIsStillAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - WithTeardown("DeletePrerequisites", funcs.AllOf( + WithTeardown("DeleteAllPrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "prerequisites/*.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "prerequisites/*.yaml"), )). diff --git a/test/e2e/pkg_test.go b/test/e2e/pkg_test.go index e0a1f6883..4c26269bb 100644 --- a/test/e2e/pkg_test.go +++ b/test/e2e/pkg_test.go @@ -41,11 +41,11 @@ func TestConfigurationPullFromPrivateRegistry(t *testing.T) { features.New("ConfigurationPullFromPrivateRegistry"). WithLabel(LabelArea, LabelAreaPkg). WithLabel(LabelSize, LabelSizeSmall). - WithSetup("ConfigurationCreated", funcs.AllOf( + WithSetup("CreateConfiguration", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "*.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "*.yaml"), )). - Assess("ConfigurationHealthyBeforeTimeout", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active())). + Assess("ConfigurationIsHealthy", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active())). WithTeardown("DeleteConfiguration", funcs.AllOf( funcs.DeleteResources(manifests, "*.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "*.yaml"), @@ -62,19 +62,21 @@ func TestConfigurationWithDependency(t *testing.T) { features.New("ConfigurationWithDependency"). WithLabel(LabelArea, LabelAreaPkg). WithLabel(LabelSize, LabelSizeSmall). - WithSetup("ReadyConfiguration", funcs.AllOf( + WithSetup("ApplyConfiguration", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "configuration.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "configuration.yaml"), )). - Assess("ConfigurationHealthyBeforeTimeout", + Assess("ConfigurationIsHealthy", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "configuration.yaml", pkgv1.Healthy(), pkgv1.Active())). - Assess("RequiredProviderHealthyBeforeTimeout", + Assess("RequiredProviderIsHealthy", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-dependency.yaml", pkgv1.Healthy(), pkgv1.Active())). - Teardown(funcs.AllOf( + // Dependencies are not automatically deleted. + WithTeardown("DeleteConfiguration", funcs.AllOf( funcs.DeleteResources(manifests, "configuration.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "configuration.yaml"), + )). + WithTeardown("DeleteRequiredProvider", funcs.AllOf( funcs.DeleteResources(manifests, "provider-dependency.yaml"), - // Dependencies are not automatically deleted. funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "provider-dependency.yaml"), )).Feature(), ) @@ -89,12 +91,12 @@ func TestProviderUpgrade(t *testing.T) { features.New("ProviderUpgrade"). WithLabel(LabelArea, LabelAreaPkg). WithLabel(LabelSize, LabelSizeSmall). - WithSetup("ReadyInitialProvider", funcs.AllOf( + WithSetup("ApplyInitialProvider", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "provider-initial.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "provider-initial.yaml"), funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "provider-initial.yaml", pkgv1.Healthy(), pkgv1.Active()), )). - WithSetup("ReadyInitialManagedResource", funcs.AllOf( + WithSetup("InitialManagedResourceIsReady", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "mr-initial.yaml"), funcs.ResourcesCreatedWithin(1*time.Minute, manifests, "mr-initial.yaml"), )). @@ -106,11 +108,11 @@ func TestProviderUpgrade(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "mr-upgrade.yaml"), funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "mr.yaml", xpv1.Available()), )). - WithTeardown("DeletedUpgradedManagedResource", funcs.AllOf( + WithTeardown("DeleteUpgradedManagedResource", funcs.AllOf( funcs.DeleteResources(manifests, "mr-upgrade.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "mr-upgrade.yaml"), )). - WithTeardown("DeletedUpgradedProvider", funcs.AllOf( + WithTeardown("DeleteUpgradedProvider", funcs.AllOf( funcs.DeleteResources(manifests, "provider-upgrade.yaml"), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, "provider-upgrade.yaml"), )).Feature(), From 41a59686c0e27c62bbe23c670229d6ec468a5062 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Fri, 30 Jun 2023 09:57:11 +0200 Subject: [PATCH 026/148] chore: address review comments Signed-off-by: Philippe Scorsolini --- test/e2e/README.md | 31 ++++++++++++------ test/e2e/apiextensions_test.go | 32 +++++++++---------- test/e2e/install_test.go | 20 ++++++------ .../{prerequisites => setup}/composition.yaml | 0 .../{prerequisites => setup}/definition.yaml | 0 .../{prerequisites => setup}/provider.yaml | 0 .../{prerequisites => setup}/composition.yaml | 0 .../{prerequisites => setup}/definition.yaml | 0 .../{prerequisites => setup}/provider.yaml | 0 .../{prerequisites => setup}/definition.yaml | 0 .../{prerequisites => setup}/provider.yaml | 0 .../{prerequisites => setup}/composition.yaml | 0 .../{prerequisites => setup}/definition.yaml | 0 .../{prerequisites => setup}/provider.yaml | 0 14 files changed, 47 insertions(+), 36 deletions(-) rename test/e2e/manifests/apiextensions/composition/minimal/{prerequisites => setup}/composition.yaml (100%) rename test/e2e/manifests/apiextensions/composition/minimal/{prerequisites => setup}/definition.yaml (100%) rename test/e2e/manifests/apiextensions/composition/minimal/{prerequisites => setup}/provider.yaml (100%) rename test/e2e/manifests/apiextensions/composition/patch-and-transform/{prerequisites => setup}/composition.yaml (100%) rename test/e2e/manifests/apiextensions/composition/patch-and-transform/{prerequisites => setup}/definition.yaml (100%) rename test/e2e/manifests/apiextensions/composition/patch-and-transform/{prerequisites => setup}/provider.yaml (100%) rename test/e2e/manifests/apiextensions/composition/validation/{prerequisites => setup}/definition.yaml (100%) rename test/e2e/manifests/apiextensions/composition/validation/{prerequisites => setup}/provider.yaml (100%) rename test/e2e/manifests/lifecycle/upgrade/{prerequisites => setup}/composition.yaml (100%) rename test/e2e/manifests/lifecycle/upgrade/{prerequisites => setup}/definition.yaml (100%) rename test/e2e/manifests/lifecycle/upgrade/{prerequisites => setup}/provider.yaml (100%) diff --git a/test/e2e/README.md b/test/e2e/README.md index 17816b06e..cc6d5e102 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -47,13 +47,24 @@ E2E_TEST_FLAGS="-test.v -test.failfast -destroy-kind-cluster=false" # local build of Crossplane in this scenario, so you'll have to do it yourself. E2E_TEST_FLAGS="-create-kind-cluster=false -destroy-kind-cluster=false -kubeconfig=$HOME/.kube/config" -# Run the CrossplaneUpgrade feature, against an existing kind cluster named "kind" (or creating it if it doesn't exist), -# without installing Crossplane first, as the feature expects the cluster to be empty, but still loading the images to -# it. Setting the tests to fail fast and not destroying the cluster afterward in order to allow debugging it. -E2E_TEST_FLAGS="-test.v -v 4 -test.failfast -destroy-kind-cluster=false -kind-cluster-name=kind -install-crossplane=false -feature=CrossplaneUpgrade" make e2e - -# Run the all tests not installing or upgrading Crossplane against the currently selected cluster where Crossplane has already been installed. -E2E_TEST_FLAGS="-test.v -v 4 -test.failfast -kubeconfig=$HOME/.kube/config -skip-labels install-crossplane=true -create-kind-cluster=false -install-crossplane=false" make go.build e2e-run-tests``` +# Run the CrossplaneUpgrade feature, against an existing kind cluster named +# "kind" (or creating it if it doesn't exist), # without installing Crossplane +# first, as the feature expects the cluster to be empty, but still loading the +# images to # it. Setting the tests to fail fast and not destroying the cluster +# afterward in order to allow debugging it. +E2E_TEST_FLAGS="-test.v -v 4 -test.failfast \ + -destroy-kind-cluster=false \ + -kind-cluster-name=kind \ + -install-crossplane=false \ + -feature=CrossplaneUpgrade" make e2e + +# Run the all tests not installing or upgrading Crossplane against the currently +# selected cluster where Crossplane has already been installed. +E2E_TEST_FLAGS="-test.v -v 4 -test.failfast \ + -kubeconfig=$HOME/.kube/config \ + -skip-labels install-crossplane=true \ + -create-kind-cluster=false \ + -install-crossplane=false" make go.build e2e-run-tests ``` ## Test Parallelism @@ -78,7 +89,7 @@ We try to follow this pattern when adding a new test: 1. Define a single feature per Test function, if possible. 1. Setup a directory of plain YAML manifests per test - i.e. test fixtures - at - `e2e/manifests//`, usually with a `prerequisites` sub-folder + `e2e/manifests//`, usually with a `setup` sub-folder containing resources to be deployed at setup phase and cleaned up during the teardown. Try to avoid reusing other feature's fixtures, as this would introduce hidden dependencies between tests. @@ -102,9 +113,9 @@ We try to follow this pattern when adding a new test: not strictly part of the feature being tested, but are needed to make it work, and actions that are needed to clean up the environment after the test has run. -1. Use the `Asses` steps to define the steps required to exercise the actual +1. Use `Assess` steps to define the steps required to exercise the actual feature at hand. -1. Use `Asses` steps to define both conditions that should hold and actions that +1. Use `Assess` steps to define both conditions that should hold and actions that should be performed. In the former case use active descriptions, e.g. `InstallProviderNop`, while in the latter use passive descriptions, e.g. `ProviderNopIsInstalled`. diff --git a/test/e2e/apiextensions_test.go b/test/e2e/apiextensions_test.go index 28d564535..cd1bb87ea 100644 --- a/test/e2e/apiextensions_test.go +++ b/test/e2e/apiextensions_test.go @@ -46,9 +46,9 @@ func TestCompositionMinimal(t *testing.T) { WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). WithSetup("PrerequisitesAreCreated", funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), + funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite()), )). Assess("ClaimCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), @@ -60,8 +60,8 @@ func TestCompositionMinimal(t *testing.T) { funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). WithTeardown("PrerequisitesAreDeleted", funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), + funcs.DeleteResources(manifests, "setup/*.yaml"), + funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "setup/*.yaml"), )). Feature(), ) @@ -79,9 +79,9 @@ func TestCompositionPatchAndTransform(t *testing.T) { WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). WithSetup("CreatePrerequisites", funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), + funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite()), )). Assess("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), @@ -97,8 +97,8 @@ func TestCompositionPatchAndTransform(t *testing.T) { funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). WithTeardown("DeleteAllPrerequisites", funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), + funcs.DeleteResources(manifests, "setup/*.yaml"), + funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "setup/*.yaml"), )). Feature(), ) @@ -135,18 +135,18 @@ func TestCompositionValidation(t *testing.T) { funcs.ReadyToTestWithin(1*time.Minute, namespace), )). WithSetup("ApplyPrerequisites", funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), - funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite()), - funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/provider.yaml", pkgv1.Healthy(), pkgv1.Active()), + funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite()), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/provider.yaml", pkgv1.Healthy(), pkgv1.Active()), )). WithTeardown("DeleteValidComposition", funcs.AllOf( funcs.DeleteResources(manifests, "*-valid.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "*-valid.yaml"), )). WithTeardown("DeletePrerequisites", funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "prerequisites/*.yaml"), + funcs.DeleteResources(manifests, "setup/*.yaml"), + funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "setup/*.yaml"), )). // Disable our feature flag. WithTeardown("DisableAlphaCompositionValidation", funcs.AllOf( diff --git a/test/e2e/install_test.go b/test/e2e/install_test.go index fe2bbe977..101b40fb3 100644 --- a/test/e2e/install_test.go +++ b/test/e2e/install_test.go @@ -55,10 +55,10 @@ func TestCrossplaneLifecycle(t *testing.T) { WithLabel(LabelSize, LabelSizeSmall). WithLabel(LabelInstallCrossplane, LabelInstallCrossplaneTrue). WithSetup("CreatePrerequisites", funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), + funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), )). - WithSetup("XRDAreEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + WithSetup("XRDAreEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite())). WithSetup("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), @@ -69,8 +69,8 @@ func TestCrossplaneLifecycle(t *testing.T) { funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). Assess("DeleteAllPrerequisites", funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "prerequisites/*.yaml"), + funcs.DeleteResources(manifests, "setup/*.yaml"), + funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "setup/*.yaml"), )). Assess("UninstallCrossplane", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUninstall(helm.WithName(helmReleaseName), helm.WithNamespace(namespace))), @@ -112,10 +112,10 @@ func TestCrossplaneLifecycle(t *testing.T) { )), funcs.ReadyToTestWithin(1*time.Minute, namespace))). Assess("CreateClaimPrerequisites", funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "prerequisites/*.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/*.yaml"), + funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), )). - Assess("XRDIsEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", apiextensionsv1.WatchingComposite())). + Assess("XRDIsEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite())). Assess("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), @@ -135,8 +135,8 @@ func TestCrossplaneLifecycle(t *testing.T) { funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). WithTeardown("DeleteAllPrerequisites", funcs.AllOf( - funcs.DeleteResources(manifests, "prerequisites/*.yaml"), - funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "prerequisites/*.yaml"), + funcs.DeleteResources(manifests, "setup/*.yaml"), + funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "setup/*.yaml"), )). Feature(), ) diff --git a/test/e2e/manifests/apiextensions/composition/minimal/prerequisites/composition.yaml b/test/e2e/manifests/apiextensions/composition/minimal/setup/composition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/minimal/prerequisites/composition.yaml rename to test/e2e/manifests/apiextensions/composition/minimal/setup/composition.yaml diff --git a/test/e2e/manifests/apiextensions/composition/minimal/prerequisites/definition.yaml b/test/e2e/manifests/apiextensions/composition/minimal/setup/definition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/minimal/prerequisites/definition.yaml rename to test/e2e/manifests/apiextensions/composition/minimal/setup/definition.yaml diff --git a/test/e2e/manifests/apiextensions/composition/minimal/prerequisites/provider.yaml b/test/e2e/manifests/apiextensions/composition/minimal/setup/provider.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/minimal/prerequisites/provider.yaml rename to test/e2e/manifests/apiextensions/composition/minimal/setup/provider.yaml diff --git a/test/e2e/manifests/apiextensions/composition/patch-and-transform/prerequisites/composition.yaml b/test/e2e/manifests/apiextensions/composition/patch-and-transform/setup/composition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/patch-and-transform/prerequisites/composition.yaml rename to test/e2e/manifests/apiextensions/composition/patch-and-transform/setup/composition.yaml diff --git a/test/e2e/manifests/apiextensions/composition/patch-and-transform/prerequisites/definition.yaml b/test/e2e/manifests/apiextensions/composition/patch-and-transform/setup/definition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/patch-and-transform/prerequisites/definition.yaml rename to test/e2e/manifests/apiextensions/composition/patch-and-transform/setup/definition.yaml diff --git a/test/e2e/manifests/apiextensions/composition/patch-and-transform/prerequisites/provider.yaml b/test/e2e/manifests/apiextensions/composition/patch-and-transform/setup/provider.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/patch-and-transform/prerequisites/provider.yaml rename to test/e2e/manifests/apiextensions/composition/patch-and-transform/setup/provider.yaml diff --git a/test/e2e/manifests/apiextensions/composition/validation/prerequisites/definition.yaml b/test/e2e/manifests/apiextensions/composition/validation/setup/definition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/validation/prerequisites/definition.yaml rename to test/e2e/manifests/apiextensions/composition/validation/setup/definition.yaml diff --git a/test/e2e/manifests/apiextensions/composition/validation/prerequisites/provider.yaml b/test/e2e/manifests/apiextensions/composition/validation/setup/provider.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/validation/prerequisites/provider.yaml rename to test/e2e/manifests/apiextensions/composition/validation/setup/provider.yaml diff --git a/test/e2e/manifests/lifecycle/upgrade/prerequisites/composition.yaml b/test/e2e/manifests/lifecycle/upgrade/setup/composition.yaml similarity index 100% rename from test/e2e/manifests/lifecycle/upgrade/prerequisites/composition.yaml rename to test/e2e/manifests/lifecycle/upgrade/setup/composition.yaml diff --git a/test/e2e/manifests/lifecycle/upgrade/prerequisites/definition.yaml b/test/e2e/manifests/lifecycle/upgrade/setup/definition.yaml similarity index 100% rename from test/e2e/manifests/lifecycle/upgrade/prerequisites/definition.yaml rename to test/e2e/manifests/lifecycle/upgrade/setup/definition.yaml diff --git a/test/e2e/manifests/lifecycle/upgrade/prerequisites/provider.yaml b/test/e2e/manifests/lifecycle/upgrade/setup/provider.yaml similarity index 100% rename from test/e2e/manifests/lifecycle/upgrade/prerequisites/provider.yaml rename to test/e2e/manifests/lifecycle/upgrade/setup/provider.yaml From dce1c6e06adfb7f4b877290946f1c8b4f4b8bfc6 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Sat, 1 Jul 2023 09:35:48 +0200 Subject: [PATCH 027/148] chore: rename test label Signed-off-by: Philippe Scorsolini --- test/e2e/README.md | 2 +- test/e2e/main_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index cc6d5e102..7d9536246 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -62,7 +62,7 @@ E2E_TEST_FLAGS="-test.v -v 4 -test.failfast \ # selected cluster where Crossplane has already been installed. E2E_TEST_FLAGS="-test.v -v 4 -test.failfast \ -kubeconfig=$HOME/.kube/config \ - -skip-labels install-crossplane=true \ + -skip-labels modify-crossplane-installation=true \ -create-kind-cluster=false \ -install-crossplane=false" make go.build e2e-run-tests ``` diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index a8ea80d8b..0a5dd79a6 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -41,7 +41,7 @@ const LabelArea = "area" // LabelInstallCrossplane is used to mark tests that are going to install // Crossplane. -const LabelInstallCrossplane = "install-crossplane" +const LabelInstallCrossplane = "modify-crossplane-installation" // LabelInstallCrossplaneTrue is used to mark tests that are going to install // or upgrade Crossplane installation. From ef877c4f1b974a0f98124d1920cb79d4cd86f8bf Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Sat, 1 Jul 2023 09:55:21 +0200 Subject: [PATCH 028/148] chore: final refactor Signed-off-by: Philippe Scorsolini --- test/e2e/apiextensions_test.go | 12 ++++++------ test/e2e/install_test.go | 20 +++++++++++--------- test/e2e/main_test.go | 32 +++++++++++++------------------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/test/e2e/apiextensions_test.go b/test/e2e/apiextensions_test.go index cd1bb87ea..d6da6a5d5 100644 --- a/test/e2e/apiextensions_test.go +++ b/test/e2e/apiextensions_test.go @@ -50,16 +50,16 @@ func TestCompositionMinimal(t *testing.T) { funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite()), )). - Assess("ClaimCreated", funcs.AllOf( + Assess("CreateClaim", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available()), )). - WithTeardown("ClaimIsDeleted", funcs.AllOf( + WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - WithTeardown("PrerequisitesAreDeleted", funcs.AllOf( + WithTeardown("DeletePrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "setup/*.yaml"), funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "setup/*.yaml"), )). @@ -96,7 +96,7 @@ func TestCompositionPatchAndTransform(t *testing.T) { funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - WithTeardown("DeleteAllPrerequisites", funcs.AllOf( + WithTeardown("DeletePrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "setup/*.yaml"), funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "setup/*.yaml"), )). @@ -128,13 +128,13 @@ func TestCompositionValidation(t *testing.T) { WithLabel(LabelStage, LabelStageAlpha). WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). - WithLabel(LabelInstallCrossplane, LabelInstallCrossplaneTrue). + WithLabel(LabelModifyCrossplaneInstallation, LabelModifyCrossplaneInstallationTrue). // Enable our feature flag. WithSetup("EnableAlphaCompositionValidation", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions(helm.WithArgs("--set args={--debug,--enable-composition-webhook-schema-validation}"))...)), funcs.ReadyToTestWithin(1*time.Minute, namespace), )). - WithSetup("ApplyPrerequisites", funcs.AllOf( + WithSetup("CreatePrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "setup/definition.yaml", apiextensionsv1.WatchingComposite()), diff --git a/test/e2e/install_test.go b/test/e2e/install_test.go index 101b40fb3..648d40b5d 100644 --- a/test/e2e/install_test.go +++ b/test/e2e/install_test.go @@ -37,11 +37,11 @@ import ( const LabelAreaLifecycle = "lifecycle" // TestCrossplaneLifecycle tests two features expecting them to be run in order: -// - Uninstall: Test that it's possible to cleanly uninstall Crossplane, even +// - CrossplaneUninstall: Test that it's possible to cleanly uninstall Crossplane, even // after having created and deleted a claim. -// - Upgrade: Test that it's possible to upgrade Crossplane from the most recent +// - CrossplaneUpgrade: Test that it's possible to upgrade Crossplane from the most recent // stable Helm chart to the one we're testing, even when a claim exists. This -// expects the Uninstall feature to have been run first. +// expects Crossplane not to be installed. // // Note: First time Installation is tested as part of the environment setup, // if not disabled explicitly. @@ -53,7 +53,7 @@ func TestCrossplaneLifecycle(t *testing.T) { features.New("CrossplaneUninstall"). WithLabel(LabelArea, LabelAreaLifecycle). WithLabel(LabelSize, LabelSizeSmall). - WithLabel(LabelInstallCrossplane, LabelInstallCrossplaneTrue). + WithLabel(LabelModifyCrossplaneInstallation, LabelModifyCrossplaneInstallationTrue). WithSetup("CreatePrerequisites", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "setup/*.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "setup/*.yaml"), @@ -68,12 +68,15 @@ func TestCrossplaneLifecycle(t *testing.T) { funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - Assess("DeleteAllPrerequisites", funcs.AllOf( + Assess("DeletePrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "setup/*.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "setup/*.yaml"), )). Assess("UninstallCrossplane", funcs.AllOf( - funcs.AsFeaturesFunc(funcs.HelmUninstall(helm.WithName(helmReleaseName), helm.WithNamespace(namespace))), + funcs.AsFeaturesFunc(funcs.HelmUninstall( + helm.WithName(helmReleaseName), + helm.WithNamespace(namespace), + )), )). // Uninstalling the Crossplane Helm chart doesn't remove its CRDs. We // want to make sure they can be deleted cleanly. If they can't, it's a @@ -128,15 +131,14 @@ func TestCrossplaneLifecycle(t *testing.T) { Assess("CoreDeploymentIsAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane")). Assess("RBACManagerDeploymentIsAvailable", funcs.DeploymentBecomesAvailableWithin(1*time.Minute, namespace, "crossplane-rbac-manager")). Assess("CoreCRDsAreEstablished", funcs.ResourcesHaveConditionWithin(1*time.Minute, crdsDir, "*.yaml", funcs.CRDInitialNamesAccepted())). - Assess("ClaimAreAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("ClaimIsStillAvailable", funcs.ResourcesHaveConditionWithin(2*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "claim.yaml"), )). - WithTeardown("DeleteAllPrerequisites", funcs.AllOf( + WithTeardown("DeletePrerequisites", funcs.AllOf( funcs.DeleteResources(manifests, "setup/*.yaml"), - funcs.ResourcesDeletedWithin(2*time.Minute, manifests, "setup/*.yaml"), + funcs.ResourcesDeletedWithin(3*time.Minute, manifests, "setup/*.yaml"), )). Feature(), ) diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 0a5dd79a6..6cb8a456a 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -17,7 +17,6 @@ limitations under the License. package e2e import ( - "context" "flag" "os" "strings" @@ -39,13 +38,14 @@ import ( // Features within an area may be split across different test functions. const LabelArea = "area" -// LabelInstallCrossplane is used to mark tests that are going to install -// Crossplane. -const LabelInstallCrossplane = "modify-crossplane-installation" +// LabelModifyCrossplaneInstallation is used to mark tests that are going to +// modify Crossplane's installation, e.g. installing, uninstalling or upgrading +// it. +const LabelModifyCrossplaneInstallation = "modify-crossplane-installation" -// LabelInstallCrossplaneTrue is used to mark tests that are going to install -// or upgrade Crossplane installation. -const LabelInstallCrossplaneTrue = "true" +// LabelModifyCrossplaneInstallationTrue is used to mark tests that are going to +// modify Crossplane's installation. +const LabelModifyCrossplaneInstallationTrue = "true" // LabelStage represents the 'stage' of a feature - alpha, beta, etc. Generally // available features have no stage label. @@ -149,11 +149,6 @@ func TestMain(m *testing.M) { } } else { cfg.WithKubeconfigFile(conf.ResolveKubeConfigFile()) - setup = []env.Func{ - func(ctx context.Context, config *envconf.Config) (context.Context, error) { - return ctx, nil - }, - } } environment = env.NewWithConfig(cfg) @@ -163,13 +158,6 @@ func TestMain(m *testing.M) { envfuncs.LoadDockerImageToCluster(clusterName, imgxfn), ) } - - // We want to destroy the cluster if we created it, but only if we created it, - // otherwise the random name will be meaningless. - if *destroy && isKindCluster { - finish = []env.Func{envfuncs.DestroyKindCluster(clusterName)} - } - if *install { setup = append(setup, envfuncs.CreateNamespace(namespace), @@ -180,6 +168,12 @@ func TestMain(m *testing.M) { // We always want to add our types to the scheme. setup = append(setup, funcs.AddCrossplaneTypesToScheme()) + // We want to destroy the cluster if we created it, but only if we created it, + // otherwise the random name will be meaningless. + if *destroy && isKindCluster { + finish = []env.Func{envfuncs.DestroyKindCluster(clusterName)} + } + environment.Setup(setup...) environment.Finish(finish...) os.Exit(environment.Run(m)) From b78c839aacaa1abb80f1ddcad6a7c2b8ac8d9d37 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jul 2023 12:03:34 +0000 Subject: [PATCH 029/148] Update github/codeql-action digest to 004c5de --- .github/workflows/ci.yml | 4 ++-- .github/workflows/scan.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5aec3d972..d14831161 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,12 @@ jobs: run: make vendor vendor.check - name: Initialize CodeQL - uses: github/codeql-action/init@f6e388ebf0efc915c6c5b165b019ee61a6746a38 # v2 + uses: github/codeql-action/init@004c5de30b6423267685b897a3d595e944f7fed5 # v2 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f6e388ebf0efc915c6c5b165b019ee61a6746a38 # v2 + uses: github/codeql-action/analyze@004c5de30b6423267685b897a3d595e944f7fed5 # v2 trivy-scan-fs: runs-on: ubuntu-22.04 diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml index c7a63611e..7e8912a3f 100644 --- a/.github/workflows/scan.yaml +++ b/.github/workflows/scan.yaml @@ -131,7 +131,7 @@ jobs: retention-days: 3 - name: Upload Trivy Scan Results To GitHub Security Tab - uses: github/codeql-action/upload-sarif@f6e388ebf0efc915c6c5b165b019ee61a6746a38 # v2 + uses: github/codeql-action/upload-sarif@004c5de30b6423267685b897a3d595e944f7fed5 # v2 with: sarif_file: 'trivy-results.sarif' category: ${{ matrix.image }}:${{ env.tag }} From 28cda1b3d50e0bb6861ad1f6327da83d3baae5bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:04:38 +0000 Subject: [PATCH 030/148] Update module golang.org/x/sys to v0.10.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0a83f147e..12e945856 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.9.0 + golang.org/x/sys v0.10.0 google.golang.org/grpc v1.56.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/protobuf v1.31.0 diff --git a/go.sum b/go.sum index 9688710c0..f192a73ee 100644 --- a/go.sum +++ b/go.sum @@ -707,8 +707,8 @@ golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= From f9f648406e33859c60c27cc1fb79cbebdde929ec Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Fri, 23 Jun 2023 09:42:38 +0200 Subject: [PATCH 031/148] fix: pull xfn images from registry configured with custom TLS certificate Additional `--ca-bundle-path` param got introduced to `xfn spark` command, enabling to specify path to custom root certificate, e.g. `/cert/domain.crt` The value can be passed as well via `CA_BUNDLE_PATH` env variable. If set, the certificate will be added to the pool of system-wide certificates and will be used for verifying the authority of the registry by each pull. Helm chart templates are adjusted so to that the custom certificate gets mounted into `crossplane-xfn` container and `CA_BUNDLE_PATH` is set properly. Additional changes: * added xfn integration tests under `test/e2e/xfn` verifying that `--ca-bundle-path` works as expected * to check if image pulling works without running the function, `--dry-run` param got introduced as well, simplifying the test setup * CI job runs the new integration tests Signed-off-by: Predrag Knezevic --- .github/workflows/ci.yml | 3 + Makefile | 5 + .../crossplane/templates/deployment.yaml | 8 + cmd/xfn/spark/spark.go | 94 +++--- internal/oci/pull.go | 24 +- test/e2e/xfn/xfn_test.go | 297 ++++++++++++++++++ 6 files changed, 388 insertions(+), 43 deletions(-) create mode 100644 test/e2e/xfn/xfn_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d14831161..4cef8c2ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -228,6 +228,9 @@ jobs: - name: Run Unit Tests run: make -j2 test + - name: Run Integration Tests + run: make test-integration + - name: Publish Unit Test Coverage uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3 with: diff --git a/Makefile b/Makefile index f31b938b1..69f0aa394 100644 --- a/Makefile +++ b/Makefile @@ -142,6 +142,11 @@ e2e.init: build e2e-tag-images e2e.run: $(KIND) $(HELM3) e2e-run-tests +# Run integration tests +test-integration: go.build do.build.image.xfn + $(GO) test ./test/e2e/xfn -test.v -tags=integration --xfn-image-ref=$(BUILD_REGISTRY)/xfn-$(SAFEHOSTARCH) + @$(OK) integration tests passed + # Update the submodules, such as the common build scripts. submodules: @git submodule sync diff --git a/cluster/charts/crossplane/templates/deployment.yaml b/cluster/charts/crossplane/templates/deployment.yaml index 94fa3c75a..eaa87261d 100644 --- a/cluster/charts/crossplane/templates/deployment.yaml +++ b/cluster/charts/crossplane/templates/deployment.yaml @@ -215,6 +215,10 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + {{- if .Values.registryCaBundleConfig.key }} + - name: CA_BUNDLE_PATH + value: "/certs/{{ .Values.registryCaBundleConfig.key }}" + {{- end}} {{- range $key, $value := .Values.xfn.extraEnvVars }} - name: {{ $key | replace "." "_" }} value: {{ $value | quote }} @@ -222,6 +226,10 @@ spec: volumeMounts: - mountPath: /xfn name: xfn-cache + {{- if .Values.registryCaBundleConfig.name }} + - mountPath: /certs + name: ca-certs + {{- end }} {{- end }} volumes: - name: package-cache diff --git a/cmd/xfn/spark/spark.go b/cmd/xfn/spark/spark.go index 7c4984bb2..aa2334d8b 100644 --- a/cmd/xfn/spark/spark.go +++ b/cmd/xfn/spark/spark.go @@ -41,6 +41,7 @@ import ( "github.com/crossplane/crossplane/internal/oci/store" "github.com/crossplane/crossplane/internal/oci/store/overlay" "github.com/crossplane/crossplane/internal/oci/store/uncompressed" + "github.com/crossplane/crossplane/internal/xpkg" ) // Error strings. @@ -75,6 +76,8 @@ type Command struct { CacheDir string `short:"c" help:"Directory used for caching function images and containers." default:"/xfn"` Runtime string `help:"OCI runtime binary to invoke." default:"crun"` MaxStdioBytes int64 `help:"Maximum size of stdout and stderr for functions." default:"0"` + DryRun bool `help:"pull images, but skip running fn container"` + CABundlePath string `help:"Additional CA bundle to use when fetching function images from registry." env:"CA_BUNDLE_PATH"` } // Run a Composition Function inside an unprivileged user namespace. Reads a @@ -127,12 +130,20 @@ func (c *Command) Run(args *start.Args) error { //nolint:gocyclo // TODO(negz): return errors.Wrap(err, errParseRef) } + opts := []oci.ImageClientOption{FromImagePullConfig(req.GetImagePullConfig())} + if c.CABundlePath != "" { + rootCA, err := xpkg.ParseCertificatesFromPath(c.CABundlePath) + if err != nil { + return errors.Wrap(err, "Cannot parse CA bundle") + } + opts = append(opts, oci.WithCustomCA(rootCA)) + } // We cache every image we pull to the filesystem. Layers are cached as // uncompressed tarballs. This allows them to be extracted quickly when // using the uncompressed.Bundler, which extracts a new root filesystem for // every container run. p := oci.NewCachingPuller(h, store.NewImage(c.CacheDir), &oci.RemoteClient{}) - img, err := p.Image(ctx, r, FromImagePullConfig(req.GetImagePullConfig())) + img, err := p.Image(ctx, r, opts...) if err != nil { return errors.Wrap(err, errPull) } @@ -155,51 +166,56 @@ func (c *Command) Run(args *start.Args) error { //nolint:gocyclo // TODO(negz): // recommended; 'run' is more for testing. In practice though run seems to // work just fine for our use case. - //nolint:gosec // Executing with user-supplied input is intentional. - cmd := exec.CommandContext(ctx, c.Runtime, "--root="+root, "run", "--bundle="+b.Path(), runID) - cmd.Stdin = bytes.NewReader(req.GetInput()) + var rsp *v1alpha1.RunFunctionResponse + if c.DryRun { + rsp = &v1alpha1.RunFunctionResponse{Output: req.GetInput()} + } else { + //nolint:gosec // Executing with user-supplied input is intentional. + cmd := exec.CommandContext(ctx, c.Runtime, "--root="+root, "run", "--bundle="+b.Path(), runID) + cmd.Stdin = bytes.NewReader(req.GetInput()) + + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } + stderrPipe, err := cmd.StderrPipe() + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } - stderrPipe, err := cmd.StderrPipe() - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } + if err := cmd.Start(); err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - if err := cmd.Start(); err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } + stdout, err := io.ReadAll(limitReaderIfNonZero(stdoutPipe, c.MaxStdioBytes)) + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } + stderr, err := io.ReadAll(limitReaderIfNonZero(stderrPipe, c.MaxStdioBytes)) + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - stdout, err := io.ReadAll(limitReaderIfNonZero(stdoutPipe, c.MaxStdioBytes)) - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } - stderr, err := io.ReadAll(limitReaderIfNonZero(stderrPipe, c.MaxStdioBytes)) - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } + if err := cmd.Wait(); err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + exitErr.Stderr = stderr + } + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - if err := cmd.Wait(); err != nil { - var exitErr *exec.ExitError - if errors.As(err, &exitErr) { - exitErr.Stderr = stderr + if err := b.Cleanup(); err != nil { + return errors.Wrap(err, errCleanupBundle) } - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } - if err := b.Cleanup(); err != nil { - return errors.Wrap(err, errCleanupBundle) + rsp = &v1alpha1.RunFunctionResponse{Output: stdout} } - - rsp := &v1alpha1.RunFunctionResponse{Output: stdout} pb, err = proto.Marshal(rsp) if err != nil { return errors.Wrap(err, errMarshalResponse) diff --git a/internal/oci/pull.go b/internal/oci/pull.go index 69e86087c..4ec4af910 100644 --- a/internal/oci/pull.go +++ b/internal/oci/pull.go @@ -18,6 +18,9 @@ package oci import ( "context" + "crypto/tls" + "crypto/x509" + "net/http" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" @@ -86,8 +89,9 @@ func (a ImagePullAuth) Authorization() (*authn.AuthConfig, error) { // ImageClientOptions configure an ImageClient. type ImageClientOptions struct { - pull ImagePullPolicy - auth *ImagePullAuth + pull ImagePullPolicy + auth *ImagePullAuth + transport *http.Transport } func parse(o ...ImageClientOption) ImageClientOptions { @@ -117,6 +121,14 @@ func WithPullAuth(a *ImagePullAuth) ImageClientOption { } } +// WithCustomCA adds given root certificates to tls client configuration +func WithCustomCA(rootCAs *x509.CertPool) ImageClientOption { + return func(c *ImageClientOptions) { + c.transport = remote.DefaultTransport.(*http.Transport).Clone() + c.transport.TLSClientConfig = &tls.Config{RootCAs: rootCAs, MinVersion: tls.VersionTLS12} + } +} + // An ImageClient is an OCI registry client. type ImageClient interface { // Image pulls an OCI image. @@ -141,13 +153,17 @@ type RemoteClient struct{} // Image fetches an image manifest. The returned image lazily pulls its layers. func (i *RemoteClient) Image(ctx context.Context, ref name.Reference, o ...ImageClientOption) (ociv1.Image, error) { opts := parse(o...) + iOpts := []remote.Option{remote.WithContext(ctx)} if opts.auth != nil { - return remote.Image(ref, remote.WithContext(ctx), remote.WithAuth(opts.auth)) + iOpts = append(iOpts, remote.WithAuth(opts.auth)) + } + if opts.transport != nil { + iOpts = append(iOpts, remote.WithTransport(opts.transport)) } if opts.pull == ImagePullPolicyNever { return nil, errors.New(errPullNever) } - return remote.Image(ref, remote.WithContext(ctx)) + return remote.Image(ref, iOpts...) } // A CachingPuller pulls OCI images. Images are pulled either from a local cache diff --git a/test/e2e/xfn/xfn_test.go b/test/e2e/xfn/xfn_test.go new file mode 100644 index 000000000..34c0ca6f0 --- /dev/null +++ b/test/e2e/xfn/xfn_test.go @@ -0,0 +1,297 @@ +//go:build integration +// +build integration + +/* +Copyright 2020 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package xfn + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "flag" + "fmt" + "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1alpha1" + "google.golang.org/protobuf/proto" + "k8s.io/apimachinery/pkg/util/wait" + "math/big" + "net" + "os" + "os/exec" + "os/user" + "path" + "strings" + "testing" + "time" +) + +var xfnImageRef *string = flag.String("xfn-image-ref", "", "xfn runner image ref") + +func TestCustomCA(t *testing.T) { + cases := map[string]struct { + body func(xfnImageRef, certDir string) error + }{ + "retrieve xfn image from private registry by setting CA cert via CLI arg": { + body: func(fnImageRef, certDir string) error { + // start xfn runner container + cmd := exec.Command("docker", + "run", "--rm", "-i", + // making that registry appears as foo.bar host inside xfn container + "--link", "registry:foo.bar", + "-v", fmt.Sprintf("%s:/certs:z", certDir), + *xfnImageRef, + "spark", "--dry-run=true", "--ca-bundle-path", "/certs/domain.crt") + return dryRun(fnImageRef, cmd) + }, + }, + "retrieve xfn image from private registry by setting CA cert via env variable": { + body: func(fnImageRef, certDir string) error { + cmd := exec.Command("docker", + "run", "--rm", "-i", + // making that registry appears as foo.bar host inside xfn container + "--link", "registry:foo.bar", + "-v", fmt.Sprintf("%s:/certs:z", certDir), + "-e", "CA_BUNDLE_PATH=/certs/domain.crt", + *xfnImageRef, + "spark", "--dry-run=true") + return dryRun(fnImageRef, cmd) + }, + }, + "xfn image pull fails if CA cert not set": { + body: func(fnImageRef, certDir string) error { + cmd := exec.Command("docker", + "run", "--rm", "-i", + // making that registry appears as foo.bar host inside xfn container + "--link", "registry:foo.bar", + "-v", fmt.Sprintf("%s:/certs:z", certDir), + *xfnImageRef, + "spark", "--dry-run=true") + err := dryRun(fnImageRef, cmd) + if err == nil { + return fmt.Errorf("Image pull should fail, but it did not") + } + return nil + }, + }, + } + reg := &ociRegistry{Port: 5000, DataDir: t.TempDir()} + certDir := t.TempDir() + t.Logf("registry datadir %s", reg.DataDir) + t.Logf("certdir %s", certDir) + + // start local registry + err := reg.Start() + + defer reg.Stop() + + if err != nil { + t.Fatal(err) + } + + // copy an image from dockerhub into the localregistry + err = copyImage("docker.io/hello-world:latest", "localhost:5000/h-w:latest") + if err != nil { + t.Fatal(err) + } + + // stop registry, but keep the images for the second registry start + err = reg.Stop() + + if err != nil { + t.Fatal(err) + } + // now, we start the registry again with TLS enable, using custom generated certificate + reg.CertDir = certDir + err = reg.Start() + if err != nil { + t.Fatal(err) + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err := tc.body("foo.bar:5000/h-w:latest", reg.CertDir) + if err != nil { + t.Fatal(err) + } + }) + } +} + +type ociRegistry struct { + Port int + DataDir string + CertDir string +} + +func (r *ociRegistry) Start() error { + u, err := user.Current() + if err != nil { + return err + } + args := []string{ + "run", + "-d", + "-u", u.Uid, + "-p", fmt.Sprintf("%d:%d", r.Port, r.Port), + "-v", fmt.Sprintf("%s:/var/lib/registry", r.DataDir), + } + if r.CertDir != "" { + args = append(args, + "-v", fmt.Sprintf("%s:/certs:z", r.CertDir), + "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", + "-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key") + if err = createCerts(r.CertDir); err != nil { + return err + } + } + args = append(args, "--name", "registry", "registry:2") + cmd := exec.Command("docker", args...) + _, err = cmd.Output() + if err != nil { + return err + } + return waitPortRead(r.Port) +} + +func (r *ociRegistry) Stop() error { + _, err := exec.Command("docker", "rm", "-f", "registry").Output() + return err +} + +func dryRun(fnImageRef string, cmd *exec.Cmd) error { + fnStdin := "fooInput" + req := &v1alpha1.RunFunctionRequest{ + Image: fnImageRef, + Input: []byte(fnStdin), + } + + out, err := proto.Marshal(req) + if err != nil { + return err + } + + cmd.Stdin = bytes.NewReader(out) + stderr := &strings.Builder{} + cmd.Stderr = stderr + out, err = cmd.Output() + if err != nil { + fmt.Println(stderr.String()) + return err + } + fmt.Println(stderr.String()) + rsp := &v1alpha1.RunFunctionResponse{} + err = proto.Unmarshal(out, rsp) + if err != nil { + return err + } + if string(rsp.Output) != fnStdin { + return fmt.Errorf("Expected %s, got %s", fnStdin, rsp.Output) + } + return nil +} + +func copyImage(srcRef, dstRef string) error { + _, err := exec.Command("docker", "pull", srcRef).Output() + if err != nil { + return err + } + _, err = exec.Command("docker", "tag", srcRef, dstRef).Output() + if err != nil { + return err + } + _, err = exec.Command("docker", "push", dstRef).Output() + return err +} + +func waitPortRead(port int) error { + return wait.PollImmediate(2*time.Second, 20*time.Second, func() (done bool, err error) { + addr := net.JoinHostPort("localhost", fmt.Sprintf("%d", port)) + conn, err := net.DialTimeout("tcp", addr, 1*time.Second) + if err != nil { + return false, nil + } + if conn != nil { + _ = conn.Close() + return true, nil + } + return false, nil + }) +} + +func createCerts(certDir string) error { + ca := &x509.Certificate{ + SerialNumber: big.NewInt(2019), + Subject: pkix.Name{ + Organization: []string{"Company, INC."}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{""}, + StreetAddress: []string{""}, + PostalCode: []string{""}, + CommonName: "foo.bar", + }, + DNSNames: []string{"foo.bar"}, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + // create our private and public key + caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return err + } + + // create the CA + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) + if err != nil { + return err + } + + // pem encode + caPEM := new(bytes.Buffer) + pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }) + + f, err := os.Create(path.Join(certDir, "domain.crt")) + if err != nil { + return err + } + defer f.Close() + f.WriteString(caPEM.String()) + + keyPEM := new(bytes.Buffer) + pem.Encode(keyPEM, &pem.Block{ + Type: "PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), + }) + + f, err = os.Create(path.Join(certDir, "domain.key")) + if err != nil { + return err + } + defer f.Close() + f.WriteString(keyPEM.String()) + + return nil +} From 1dc313b4ff7990dfae4565a2cad36ad1d7d3154d Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Sat, 1 Jul 2023 00:24:02 +0200 Subject: [PATCH 032/148] reverted integration tests in favor of e2e ones Signed-off-by: Predrag Knezevic --- .github/workflows/ci.yml | 5 +- Makefile | 17 +- cmd/crossplane/core/core.go | 3 +- cmd/xfn/spark/spark.go | 86 +++-- go.mod | 2 +- internal/oci/certs.go | 48 +++ internal/xpkg/fetch.go | 25 -- test/e2e/funcs/feature.go | 11 + .../functions/private-registry/claim.yaml | 9 + .../private-registry/composition.yaml | 39 +++ test/e2e/testdata/images/labelizer/Dockerfile | 6 + .../testdata/images/labelizer/labelizer.sh | 3 + test/e2e/xfn/xfn_test.go | 297 ----------------- test/e2e/xfn_test.go | 303 ++++++++++++++++++ 14 files changed, 472 insertions(+), 382 deletions(-) create mode 100644 internal/oci/certs.go create mode 100644 test/e2e/manifests/apiextensions/composition/functions/private-registry/claim.yaml create mode 100644 test/e2e/manifests/apiextensions/composition/functions/private-registry/composition.yaml create mode 100644 test/e2e/testdata/images/labelizer/Dockerfile create mode 100755 test/e2e/testdata/images/labelizer/labelizer.sh delete mode 100644 test/e2e/xfn/xfn_test.go create mode 100644 test/e2e/xfn_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cef8c2ac..dfecb29df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -228,9 +228,6 @@ jobs: - name: Run Unit Tests run: make -j2 test - - name: Run Integration Tests - run: make test-integration - - name: Publish Unit Test Coverage uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3 with: @@ -243,7 +240,7 @@ jobs: if: needs.detect-noop.outputs.noop != 'true' strategy: matrix: - area: [lifecycle, pkg, apiextensions] + area: [lifecycle, pkg, apiextensions, xfn] steps: - name: Setup QEMU diff --git a/Makefile b/Makefile index 69f0aa394..0ec7adc25 100644 --- a/Makefile +++ b/Makefile @@ -116,11 +116,17 @@ cobertura: grep -v zz_generated.deepcopy | \ $(GOCOVER_COBERTURA) > $(GO_TEST_OUTPUT)/cobertura-coverage.xml -e2e-tag-images: +e2e.test.images: + @$(INFO) Building E2E test images + @docker build --load -t $(BUILD_REGISTRY)/fn-labelizer-$(TARGETARCH) test/e2e/testdata/images/labelizer + @$(OK) Built E2E test images + +e2e-tag-images: e2e.test.images @$(INFO) Tagging E2E test images @docker tag $(BUILD_REGISTRY)/$(PROJECT_NAME)-$(TARGETARCH) crossplane-e2e/$(PROJECT_NAME):latest || $(FAIL) @docker tag $(BUILD_REGISTRY)/xfn-$(TARGETARCH) crossplane-e2e/xfn:latest || $(FAIL) - @$(OK) Tagged E2E test images crossplane-e2e/$(PROJECT_NAME):latest crossplane-e2e/xfn:latest + @docker tag $(BUILD_REGISTRY)/fn-labelizer-$(TARGETARCH) crossplane-e2e/fn-labelizer:latest || $(FAIL) + @$(OK) Tagged E2E test images # NOTE(negz): There's already a go.test.integration target, but it's weird. # This relies on make build building the e2e binary. @@ -142,11 +148,6 @@ e2e.init: build e2e-tag-images e2e.run: $(KIND) $(HELM3) e2e-run-tests -# Run integration tests -test-integration: go.build do.build.image.xfn - $(GO) test ./test/e2e/xfn -test.v -tags=integration --xfn-image-ref=$(BUILD_REGISTRY)/xfn-$(SAFEHOSTARCH) - @$(OK) integration tests passed - # Update the submodules, such as the common build scripts. submodules: @git submodule sync @@ -177,7 +178,7 @@ run: go.build @# To see other arguments that can be provided, run the command with --help instead $(GO_OUT_DIR)/$(PROJECT_NAME) core start --debug -.PHONY: manifests cobertura submodules fallthrough test-integration run install-crds uninstall-crds gen-kustomize-crds e2e-tests-compile +.PHONY: manifests cobertura submodules fallthrough test-integration run install-crds uninstall-crds gen-kustomize-crds e2e-tests-compile e2e.test.images # ==================================================================================== # Special Targets diff --git a/cmd/crossplane/core/core.go b/cmd/crossplane/core/core.go index 50d8e3a5d..88ada7f27 100644 --- a/cmd/crossplane/core/core.go +++ b/cmd/crossplane/core/core.go @@ -47,6 +47,7 @@ import ( pkgcontroller "github.com/crossplane/crossplane/internal/controller/pkg/controller" "github.com/crossplane/crossplane/internal/features" "github.com/crossplane/crossplane/internal/initializer" + "github.com/crossplane/crossplane/internal/oci" "github.com/crossplane/crossplane/internal/transport" "github.com/crossplane/crossplane/internal/validation/apiextensions/v1/composition" "github.com/crossplane/crossplane/internal/xpkg" @@ -233,7 +234,7 @@ func (c *startCommand) Run(s *runtime.Scheme, log logging.Logger) error { //noli } if c.CABundlePath != "" { - rootCAs, err := xpkg.ParseCertificatesFromPath(c.CABundlePath) + rootCAs, err := oci.ParseCertificatesFromPath(c.CABundlePath) if err != nil { return errors.Wrap(err, "Cannot parse CA bundle") } diff --git a/cmd/xfn/spark/spark.go b/cmd/xfn/spark/spark.go index aa2334d8b..26dfdb5eb 100644 --- a/cmd/xfn/spark/spark.go +++ b/cmd/xfn/spark/spark.go @@ -41,7 +41,6 @@ import ( "github.com/crossplane/crossplane/internal/oci/store" "github.com/crossplane/crossplane/internal/oci/store/overlay" "github.com/crossplane/crossplane/internal/oci/store/uncompressed" - "github.com/crossplane/crossplane/internal/xpkg" ) // Error strings. @@ -76,7 +75,6 @@ type Command struct { CacheDir string `short:"c" help:"Directory used for caching function images and containers." default:"/xfn"` Runtime string `help:"OCI runtime binary to invoke." default:"crun"` MaxStdioBytes int64 `help:"Maximum size of stdout and stderr for functions." default:"0"` - DryRun bool `help:"pull images, but skip running fn container"` CABundlePath string `help:"Additional CA bundle to use when fetching function images from registry." env:"CA_BUNDLE_PATH"` } @@ -132,7 +130,7 @@ func (c *Command) Run(args *start.Args) error { //nolint:gocyclo // TODO(negz): opts := []oci.ImageClientOption{FromImagePullConfig(req.GetImagePullConfig())} if c.CABundlePath != "" { - rootCA, err := xpkg.ParseCertificatesFromPath(c.CABundlePath) + rootCA, err := oci.ParseCertificatesFromPath(c.CABundlePath) if err != nil { return errors.Wrap(err, "Cannot parse CA bundle") } @@ -166,56 +164,52 @@ func (c *Command) Run(args *start.Args) error { //nolint:gocyclo // TODO(negz): // recommended; 'run' is more for testing. In practice though run seems to // work just fine for our use case. - var rsp *v1alpha1.RunFunctionResponse - if c.DryRun { - rsp = &v1alpha1.RunFunctionResponse{Output: req.GetInput()} - } else { - //nolint:gosec // Executing with user-supplied input is intentional. - cmd := exec.CommandContext(ctx, c.Runtime, "--root="+root, "run", "--bundle="+b.Path(), runID) - cmd.Stdin = bytes.NewReader(req.GetInput()) + //nolint:gosec // Executing with user-supplied input is intentional. + cmd := exec.CommandContext(ctx, c.Runtime, "--root="+root, "run", "--bundle="+b.Path(), runID) + cmd.Stdin = bytes.NewReader(req.GetInput()) - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } - stderrPipe, err := cmd.StderrPipe() - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } - - if err := cmd.Start(); err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } + stderrPipe, err := cmd.StderrPipe() + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - stdout, err := io.ReadAll(limitReaderIfNonZero(stdoutPipe, c.MaxStdioBytes)) - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } - stderr, err := io.ReadAll(limitReaderIfNonZero(stderrPipe, c.MaxStdioBytes)) - if err != nil { - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } + if err := cmd.Start(); err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - if err := cmd.Wait(); err != nil { - var exitErr *exec.ExitError - if errors.As(err, &exitErr) { - exitErr.Stderr = stderr - } - _ = b.Cleanup() - return errors.Wrap(err, errRuntime) - } + stdout, err := io.ReadAll(limitReaderIfNonZero(stdoutPipe, c.MaxStdioBytes)) + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } + stderr, err := io.ReadAll(limitReaderIfNonZero(stderrPipe, c.MaxStdioBytes)) + if err != nil { + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - if err := b.Cleanup(); err != nil { - return errors.Wrap(err, errCleanupBundle) + if err := cmd.Wait(); err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + exitErr.Stderr = stderr } + _ = b.Cleanup() + return errors.Wrap(err, errRuntime) + } - rsp = &v1alpha1.RunFunctionResponse{Output: stdout} + if err := b.Cleanup(); err != nil { + return errors.Wrap(err, errCleanupBundle) } + + rsp := &v1alpha1.RunFunctionResponse{Output: stdout} + pb, err = proto.Marshal(rsp) if err != nil { return errors.Wrap(err, errMarshalResponse) diff --git a/go.mod b/go.mod index 12e945856..e260d2fe1 100644 --- a/go.mod +++ b/go.mod @@ -154,7 +154,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/tetratelabs/wazero v1.2.1 // indirect github.com/vbatts/tar-split v0.11.3 // indirect - github.com/vladimirvivien/gexe v0.2.0 // indirect + github.com/vladimirvivien/gexe v0.2.0 go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect diff --git a/internal/oci/certs.go b/internal/oci/certs.go new file mode 100644 index 000000000..d1e3d2d51 --- /dev/null +++ b/internal/oci/certs.go @@ -0,0 +1,48 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oci + +import ( + "crypto/x509" + "os" + "path/filepath" + + "github.com/crossplane/crossplane-runtime/pkg/errors" +) + +// ParseCertificatesFromPath parses PEM file containing extra x509 +// certificates(s) and combines them with the built in root CA CertPool. +func ParseCertificatesFromPath(path string) (*x509.CertPool, error) { + // Get the SystemCertPool, continue with an empty pool on error + rootCAs, _ := x509.SystemCertPool() + if rootCAs == nil { + rootCAs = x509.NewCertPool() + } + + // Read in the cert file + certs, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return nil, errors.Wrapf(err, "Failed to append %q to RootCAs", path) + } + + // Append our cert to the system pool + if ok := rootCAs.AppendCertsFromPEM(certs); !ok { + return nil, errors.Errorf("No certificates could be parsed from %q", path) + } + + return rootCAs, nil +} diff --git a/internal/xpkg/fetch.go b/internal/xpkg/fetch.go index c29135f1e..5b10f3321 100644 --- a/internal/xpkg/fetch.go +++ b/internal/xpkg/fetch.go @@ -22,8 +22,6 @@ import ( "crypto/x509" "io" "net/http" - "os" - "path/filepath" "github.com/google/go-containerregistry/pkg/authn/k8schain" "github.com/google/go-containerregistry/pkg/name" @@ -64,29 +62,6 @@ type K8sFetcher struct { // FetcherOpt can be used to add optional parameters to NewK8sFetcher type FetcherOpt func(k *K8sFetcher) error -// ParseCertificatesFromPath parses PEM file containing extra x509 -// certificates(s) and combines them with the built in root CA CertPool. -func ParseCertificatesFromPath(path string) (*x509.CertPool, error) { - // Get the SystemCertPool, continue with an empty pool on error - rootCAs, _ := x509.SystemCertPool() - if rootCAs == nil { - rootCAs = x509.NewCertPool() - } - - // Read in the cert file - certs, err := os.ReadFile(filepath.Clean(path)) - if err != nil { - return nil, errors.Wrapf(err, "Failed to append %q to RootCAs", path) - } - - // Append our cert to the system pool - if ok := rootCAs.AppendCertsFromPEM(certs); !ok { - return nil, errors.Errorf("No certificates could be parsed from %q", path) - } - - return rootCAs, nil -} - // WithCustomCA is a FetcherOpt that can be used to add a custom CA bundle to a K8sFetcher. func WithCustomCA(rootCAs *x509.CertPool) FetcherOpt { return func(k *K8sFetcher) error { diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index 1a942f05d..e3658144b 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -385,6 +385,17 @@ func DeleteResources(dir, pattern string) features.Func { } } +// CreateNamespace creates the given namespace +func CreateNamespace(name string) features.Func { + return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: name}} + if err := config.Client().Resources().Create(ctx, ns); err != nil { + t.Fatalf(fmt.Sprintf("error creating namespace %s", name), err) + } + return ctx + } +} + // asUnstructured turns an arbitrary runtime.Object into an *Unstructured. If // it's already a concrete *Unstructured it just returns it, otherwise it // round-trips it through JSON encoding. This is necessary because types that diff --git a/test/e2e/manifests/apiextensions/composition/functions/private-registry/claim.yaml b/test/e2e/manifests/apiextensions/composition/functions/private-registry/claim.yaml new file mode 100644 index 000000000..c4599aa85 --- /dev/null +++ b/test/e2e/manifests/apiextensions/composition/functions/private-registry/claim.yaml @@ -0,0 +1,9 @@ +apiVersion: nop.example.org/v1alpha1 +kind: NopResource +metadata: + name: fn-labelizer + namespace: default +spec: + coolField: example + compositionRef: + name: fn.xnopresources.nop.example.org \ No newline at end of file diff --git a/test/e2e/manifests/apiextensions/composition/functions/private-registry/composition.yaml b/test/e2e/manifests/apiextensions/composition/functions/private-registry/composition.yaml new file mode 100644 index 000000000..f20c850fb --- /dev/null +++ b/test/e2e/manifests/apiextensions/composition/functions/private-registry/composition.yaml @@ -0,0 +1,39 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: fn.xnopresources.nop.example.org + labels: + provider: provider-nop +spec: + compositeTypeRef: + apiVersion: nop.example.org/v1alpha1 + kind: XNopResource + resources: + - name: nopinstance1 + base: + apiVersion: nop.crossplane.io/v1alpha1 + kind: NopResource + spec: + forProvider: + conditionAfter: + - conditionType: Ready + conditionStatus: "False" + time: 0s + - conditionType: Ready + conditionStatus: "True" + time: 10s + - conditionType: Synced + conditionStatus: "False" + time: 0s + - conditionType: Synced + conditionStatus: "True" + time: 10s + writeConnectionSecretsToRef: + namespace: crossplane-system + name: nop-example-resource + functions: + - name: labelizer + type: Container + container: + image: private-docker-registry.reg.svc.cluster.local:5000/fn-labelizer:latest + imagePullPolicy: Always \ No newline at end of file diff --git a/test/e2e/testdata/images/labelizer/Dockerfile b/test/e2e/testdata/images/labelizer/Dockerfile new file mode 100644 index 000000000..a399088f0 --- /dev/null +++ b/test/e2e/testdata/images/labelizer/Dockerfile @@ -0,0 +1,6 @@ +FROM mikefarah/yq:4.34.1 + +COPY labelizer.sh /bin +USER root + +ENTRYPOINT ["/bin/labelizer.sh"] \ No newline at end of file diff --git a/test/e2e/testdata/images/labelizer/labelizer.sh b/test/e2e/testdata/images/labelizer/labelizer.sh new file mode 100755 index 000000000..e0bfb2306 --- /dev/null +++ b/test/e2e/testdata/images/labelizer/labelizer.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +yq '(.desired.resources[] | .resource.metadata.labels) |= {"labelizer.xfn.crossplane.io/processed": "true"} + .' diff --git a/test/e2e/xfn/xfn_test.go b/test/e2e/xfn/xfn_test.go deleted file mode 100644 index 34c0ca6f0..000000000 --- a/test/e2e/xfn/xfn_test.go +++ /dev/null @@ -1,297 +0,0 @@ -//go:build integration -// +build integration - -/* -Copyright 2020 The Crossplane Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package xfn - -import ( - "bytes" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "flag" - "fmt" - "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1alpha1" - "google.golang.org/protobuf/proto" - "k8s.io/apimachinery/pkg/util/wait" - "math/big" - "net" - "os" - "os/exec" - "os/user" - "path" - "strings" - "testing" - "time" -) - -var xfnImageRef *string = flag.String("xfn-image-ref", "", "xfn runner image ref") - -func TestCustomCA(t *testing.T) { - cases := map[string]struct { - body func(xfnImageRef, certDir string) error - }{ - "retrieve xfn image from private registry by setting CA cert via CLI arg": { - body: func(fnImageRef, certDir string) error { - // start xfn runner container - cmd := exec.Command("docker", - "run", "--rm", "-i", - // making that registry appears as foo.bar host inside xfn container - "--link", "registry:foo.bar", - "-v", fmt.Sprintf("%s:/certs:z", certDir), - *xfnImageRef, - "spark", "--dry-run=true", "--ca-bundle-path", "/certs/domain.crt") - return dryRun(fnImageRef, cmd) - }, - }, - "retrieve xfn image from private registry by setting CA cert via env variable": { - body: func(fnImageRef, certDir string) error { - cmd := exec.Command("docker", - "run", "--rm", "-i", - // making that registry appears as foo.bar host inside xfn container - "--link", "registry:foo.bar", - "-v", fmt.Sprintf("%s:/certs:z", certDir), - "-e", "CA_BUNDLE_PATH=/certs/domain.crt", - *xfnImageRef, - "spark", "--dry-run=true") - return dryRun(fnImageRef, cmd) - }, - }, - "xfn image pull fails if CA cert not set": { - body: func(fnImageRef, certDir string) error { - cmd := exec.Command("docker", - "run", "--rm", "-i", - // making that registry appears as foo.bar host inside xfn container - "--link", "registry:foo.bar", - "-v", fmt.Sprintf("%s:/certs:z", certDir), - *xfnImageRef, - "spark", "--dry-run=true") - err := dryRun(fnImageRef, cmd) - if err == nil { - return fmt.Errorf("Image pull should fail, but it did not") - } - return nil - }, - }, - } - reg := &ociRegistry{Port: 5000, DataDir: t.TempDir()} - certDir := t.TempDir() - t.Logf("registry datadir %s", reg.DataDir) - t.Logf("certdir %s", certDir) - - // start local registry - err := reg.Start() - - defer reg.Stop() - - if err != nil { - t.Fatal(err) - } - - // copy an image from dockerhub into the localregistry - err = copyImage("docker.io/hello-world:latest", "localhost:5000/h-w:latest") - if err != nil { - t.Fatal(err) - } - - // stop registry, but keep the images for the second registry start - err = reg.Stop() - - if err != nil { - t.Fatal(err) - } - // now, we start the registry again with TLS enable, using custom generated certificate - reg.CertDir = certDir - err = reg.Start() - if err != nil { - t.Fatal(err) - } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - err := tc.body("foo.bar:5000/h-w:latest", reg.CertDir) - if err != nil { - t.Fatal(err) - } - }) - } -} - -type ociRegistry struct { - Port int - DataDir string - CertDir string -} - -func (r *ociRegistry) Start() error { - u, err := user.Current() - if err != nil { - return err - } - args := []string{ - "run", - "-d", - "-u", u.Uid, - "-p", fmt.Sprintf("%d:%d", r.Port, r.Port), - "-v", fmt.Sprintf("%s:/var/lib/registry", r.DataDir), - } - if r.CertDir != "" { - args = append(args, - "-v", fmt.Sprintf("%s:/certs:z", r.CertDir), - "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", - "-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key") - if err = createCerts(r.CertDir); err != nil { - return err - } - } - args = append(args, "--name", "registry", "registry:2") - cmd := exec.Command("docker", args...) - _, err = cmd.Output() - if err != nil { - return err - } - return waitPortRead(r.Port) -} - -func (r *ociRegistry) Stop() error { - _, err := exec.Command("docker", "rm", "-f", "registry").Output() - return err -} - -func dryRun(fnImageRef string, cmd *exec.Cmd) error { - fnStdin := "fooInput" - req := &v1alpha1.RunFunctionRequest{ - Image: fnImageRef, - Input: []byte(fnStdin), - } - - out, err := proto.Marshal(req) - if err != nil { - return err - } - - cmd.Stdin = bytes.NewReader(out) - stderr := &strings.Builder{} - cmd.Stderr = stderr - out, err = cmd.Output() - if err != nil { - fmt.Println(stderr.String()) - return err - } - fmt.Println(stderr.String()) - rsp := &v1alpha1.RunFunctionResponse{} - err = proto.Unmarshal(out, rsp) - if err != nil { - return err - } - if string(rsp.Output) != fnStdin { - return fmt.Errorf("Expected %s, got %s", fnStdin, rsp.Output) - } - return nil -} - -func copyImage(srcRef, dstRef string) error { - _, err := exec.Command("docker", "pull", srcRef).Output() - if err != nil { - return err - } - _, err = exec.Command("docker", "tag", srcRef, dstRef).Output() - if err != nil { - return err - } - _, err = exec.Command("docker", "push", dstRef).Output() - return err -} - -func waitPortRead(port int) error { - return wait.PollImmediate(2*time.Second, 20*time.Second, func() (done bool, err error) { - addr := net.JoinHostPort("localhost", fmt.Sprintf("%d", port)) - conn, err := net.DialTimeout("tcp", addr, 1*time.Second) - if err != nil { - return false, nil - } - if conn != nil { - _ = conn.Close() - return true, nil - } - return false, nil - }) -} - -func createCerts(certDir string) error { - ca := &x509.Certificate{ - SerialNumber: big.NewInt(2019), - Subject: pkix.Name{ - Organization: []string{"Company, INC."}, - Country: []string{"US"}, - Province: []string{""}, - Locality: []string{""}, - StreetAddress: []string{""}, - PostalCode: []string{""}, - CommonName: "foo.bar", - }, - DNSNames: []string{"foo.bar"}, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), - IsCA: true, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - - // create our private and public key - caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - return err - } - - // create the CA - caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) - if err != nil { - return err - } - - // pem encode - caPEM := new(bytes.Buffer) - pem.Encode(caPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: caBytes, - }) - - f, err := os.Create(path.Join(certDir, "domain.crt")) - if err != nil { - return err - } - defer f.Close() - f.WriteString(caPEM.String()) - - keyPEM := new(bytes.Buffer) - pem.Encode(keyPEM, &pem.Block{ - Type: "PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), - }) - - f, err = os.Create(path.Join(certDir, "domain.key")) - if err != nil { - return err - } - defer f.Close() - f.WriteString(keyPEM.String()) - - return nil -} diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go new file mode 100644 index 000000000..6d9984065 --- /dev/null +++ b/test/e2e/xfn_test.go @@ -0,0 +1,303 @@ +/* +Copyright 2023 The Crossplane Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package e2e + +import ( + "bytes" + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "io" + "math/big" + "reflect" + "testing" + "time" + + "github.com/vladimirvivien/gexe" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + client2 "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/features" + "sigs.k8s.io/e2e-framework/third_party/helm" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + + v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" + "github.com/crossplane/crossplane/test/e2e/funcs" +) + +func TestFunctions(t *testing.T) { + + manifests := "test/e2e/manifests/apiextensions/composition/functions/private-registry" + environment.Test(t, + features.New("PullImageFromPrivateRegistryWithCustomCert"). + WithLabel(LabelArea, "xfn"). + Setup(funcs.CreateNamespace("reg")). + Setup(CreateTLSCertificateAsSecret("private-docker-registry.reg.svc.cluster.local", "reg")). + Setup(InstallDockerRegistry()). + Setup(CopyImagesToRegistry()). + Setup(CrossplaneDeployedWithFunctionsEnabled()). + Setup(ProvideNopDeployed()). + Assess("CompositionWithFunctionIsCreated", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "composition.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "composition.yaml"), + )). + Assess("ClaimIsCreated", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), + )). + Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ManagedResourcesProcessedByFunction", ManagedResourcedProcessedByFunction()). + Teardown(funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...))). + Feature(), + ) +} + +func resourceGetter(ctx context.Context, t *testing.T, config *envconf.Config) func(string, string, string, string) *unstructured.Unstructured { + return func(name string, namespace string, apiVersion string, kind string) *unstructured.Unstructured { + client := config.Client().Resources().GetControllerRuntimeClient() + u := &unstructured.Unstructured{} + gv, err := schema.ParseGroupVersion(apiVersion) + if err != nil { + t.Fatal(err) + } + u.SetGroupVersionKind(gv.WithKind(kind)) + if err := client.Get(ctx, client2.ObjectKey{Name: name, Namespace: namespace}, u); err != nil { + t.Fatal("cannot get claim", err) + } + return u + } +} +func resourceValue(t *testing.T, u *unstructured.Unstructured, path ...string) map[string]string { + f, found, err := unstructured.NestedStringMap(u.Object, path...) + if err != nil { + t.Fatal(err) + } + if !found { + t.Fatalf("field not found at path %v", path) + } + return f +} + +func resourceSliceValue(t *testing.T, u *unstructured.Unstructured, path ...string) []map[string]string { + f, found, err := unstructured.NestedSlice(u.Object, path...) + if err != nil { + t.Fatal(err) + } + if !found { + t.Fatalf("field not found at path %v", path) + } + var s []map[string]string + for _, v := range f { + if vv, ok := v.(map[string]interface{}); ok { + s = append(s, asMapOfStrings(vv)) + } else { + t.Fatalf("not a map[string]string: %v type %s", v, reflect.TypeOf(v)) + } + } + return s +} + +func asMapOfStrings(m map[string]interface{}) map[string]string { + r := make(map[string]string) + for k, v := range m { + r[k] = fmt.Sprintf("%v", v) + } + return r +} + +// ManagedResourcedProcessedByFunction asserts that MRs contains the requested label +func ManagedResourcedProcessedByFunction() features.Func { + + return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + labelName := "labelizer.xfn.crossplane.io/processed" + rg := resourceGetter(ctx, t, config) + claim := rg("fn-labelizer", "default", "nop.example.org/v1alpha1", "NopResource") + r := resourceValue(t, claim, "spec", "resourceRef") + + xr := rg(r["name"], "default", r["apiVersion"], r["kind"]) + mrefs := resourceSliceValue(t, xr, "spec", "resourceRefs") + for _, mref := range mrefs { + mr := rg(mref["name"], "default", mref["apiVersion"], mref["kind"]) + l, found := mr.GetLabels()[labelName] + if !found { + t.Fatalf("managed resource %v was not processed by function", mr) + } + if l != "true" { + t.Fatalf("Expected label %v value to be true, but got %v", labelName, l) + } + } + return ctx + } +} + +// CreateTLSCertificateAsSecret for given dns name and store the secret in the given namespace +func CreateTLSCertificateAsSecret(dnsName string, ns string) features.Func { + return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + caPem, keyPem, err := createCert(dnsName) + if err != nil { + t.Fatal(err) + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reg-cert", + Namespace: ns, + }, + Type: corev1.SecretTypeTLS, + StringData: map[string]string{ + "tls.crt": caPem, + "tls.key": keyPem, + }, + } + client := config.Client().Resources() + if err := client.Create(ctx, secret); err != nil { + t.Fatalf("Cannot create secret %s: %v", secret.Name, err) + } + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reg-ca", + Namespace: namespace, + }, + Data: map[string]string{ + "domain.crt": caPem, + }, + } + if err := client.Create(ctx, configMap); err != nil { + t.Fatalf("Cannot create config %s: %v", configMap.Name, err) + } + return ctx + } +} + +// CopyImagesToRegistry copies fn images to private registry +func CopyImagesToRegistry() features.Func { + return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + pfw := gexe.StartProc("kubectl port-forward service/private-docker-registry -n reg 32000:5000") + defer func() { + pfw.Kill() + pfw.Wait() + out, _ := io.ReadAll(pfw.Out()) + t.Log("out", string(out), "err", pfw.Err()) + }() + time.Sleep(20 * time.Second) + _ = gexe.Run("docker tag crossplane-e2e/fn-labelizer:latest localhost:32000/fn-labelizer:latest") + p := gexe.RunProc("docker push localhost:32000/fn-labelizer:latest") + if p.ExitCode() != 0 { + out, _ := io.ReadAll(p.Out()) + t.Fatalf("copying image to registry not successful, exit code %v std out %v std err %v", p.ExitCode(), string(out), p.Err()) + } + return ctx + } +} + +// InstallDockerRegistry with custom TLS +func InstallDockerRegistry() features.Func { + return funcs.AsFeaturesFunc(funcs.HelmInstall( + helm.WithName("private"), + helm.WithNamespace("reg"), + helm.WithWait(), + helm.WithChart("https://helm.twun.io/docker-registry-2.2.1.tgz"), + helm.WithArgs( + "--set service.type=NodePort", + "--set service.nodePort=32000", + "--set tlsSecretName=reg-cert", + ), + )) +} + +// CrossplaneDeployedWithFunctionsEnabled asserts that crossplane deployment with composition functions is enabled +func CrossplaneDeployedWithFunctionsEnabled() features.Func { + return funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade( + HelmOptions( + helm.WithArgs( + "--set args={--debug,--enable-composition-functions}", + "--set xfn.enabled=true", + "--set xfn.args={--debug}", + "--set registryCaBundleConfig.name=reg-ca", + "--set registryCaBundleConfig.key=domain.crt", + ))...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + ) +} + +// ProvideNopDeployed assets that provider-nop is deployed and healthy +func ProvideNopDeployed() features.Func { + manifests := "test/e2e/manifests/apiextensions/composition/minimal/prerequisites" + return funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "provider.yaml"), + funcs.ApplyResources(FieldManager, manifests, "definition.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "provider.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "definition.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "definition.yaml", v1.WatchingComposite()), + ) +} + +func createCert(dnsName string) (string, string, error) { + ca := &x509.Certificate{ + SerialNumber: big.NewInt(2019), + Subject: pkix.Name{ + Organization: []string{"Company, INC."}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{""}, + StreetAddress: []string{""}, + PostalCode: []string{""}, + CommonName: dnsName, + }, + DNSNames: []string{dnsName}, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + // create our private and public key + caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return "", "", err + } + + // create the CA + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) + if err != nil { + return "", "", err + } + + // pem encode + caPEM := new(bytes.Buffer) + pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }) + + keyPEM := new(bytes.Buffer) + pem.Encode(keyPEM, &pem.Block{ + Type: "PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), + }) + + return caPEM.String(), keyPEM.String(), nil +} From a7e46aca99babf7f19fae86444ae662126a31d3b Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Sat, 1 Jul 2023 08:20:21 +0200 Subject: [PATCH 033/148] copy images using skopeo Signed-off-by: Predrag Knezevic --- cmd/xfn/spark/spark.go | 1 - go.mod | 2 ++ go.sum | 2 ++ test/e2e/xfn_test.go | 57 +++++++++++++++++++++++++++--------------- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/cmd/xfn/spark/spark.go b/cmd/xfn/spark/spark.go index 26dfdb5eb..09b9f043f 100644 --- a/cmd/xfn/spark/spark.go +++ b/cmd/xfn/spark/spark.go @@ -209,7 +209,6 @@ func (c *Command) Run(args *start.Args) error { //nolint:gocyclo // TODO(negz): } rsp := &v1alpha1.RunFunctionResponse{Output: stdout} - pb, err = proto.Marshal(rsp) if err != nil { return errors.Wrap(err, errMarshalResponse) diff --git a/go.mod b/go.mod index e260d2fe1..a42f658b1 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,8 @@ require ( sigs.k8s.io/yaml v1.3.0 ) +require golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df + require ( cloud.google.com/go/compute v1.19.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect diff --git a/go.sum b/go.sum index f192a73ee..7b13bccb0 100644 --- a/go.sum +++ b/go.sum @@ -558,6 +558,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 6d9984065..f64aef95d 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -30,11 +30,13 @@ import ( "time" "github.com/vladimirvivien/gexe" + "golang.org/x/exp/slices" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" client2 "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/e2e-framework/klient/wait" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/features" "sigs.k8s.io/e2e-framework/third_party/helm" @@ -67,7 +69,6 @@ func TestFunctions(t *testing.T) { )). Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). Assess("ManagedResourcesProcessedByFunction", ManagedResourcedProcessedByFunction()). - Teardown(funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...))). Feature(), ) } @@ -137,14 +138,21 @@ func ManagedResourcedProcessedByFunction() features.Func { xr := rg(r["name"], "default", r["apiVersion"], r["kind"]) mrefs := resourceSliceValue(t, xr, "spec", "resourceRefs") for _, mref := range mrefs { - mr := rg(mref["name"], "default", mref["apiVersion"], mref["kind"]) - l, found := mr.GetLabels()[labelName] - if !found { - t.Fatalf("managed resource %v was not processed by function", mr) - } - if l != "true" { - t.Fatalf("Expected label %v value to be true, but got %v", labelName, l) + err := wait.For(func() (done bool, err error) { + mr := rg(mref["name"], "default", mref["apiVersion"], mref["kind"]) + l, found := mr.GetLabels()[labelName] + if !found { + return false, nil + } + if l != "true" { + return false, nil + } + return true, nil + }, wait.WithTimeout(5*time.Minute)) + if err != nil { + t.Fatalf("Expected label %v value to be true", labelName) } + } return ctx } @@ -192,18 +200,24 @@ func CreateTLSCertificateAsSecret(dnsName string, ns string) features.Func { // CopyImagesToRegistry copies fn images to private registry func CopyImagesToRegistry() features.Func { return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - pfw := gexe.StartProc("kubectl port-forward service/private-docker-registry -n reg 32000:5000") - defer func() { - pfw.Kill() - pfw.Wait() - out, _ := io.ReadAll(pfw.Out()) - t.Log("out", string(out), "err", pfw.Err()) - }() - time.Sleep(20 * time.Second) - _ = gexe.Run("docker tag crossplane-e2e/fn-labelizer:latest localhost:32000/fn-labelizer:latest") - p := gexe.RunProc("docker push localhost:32000/fn-labelizer:latest") + nodes := &corev1.NodeList{} + if err := config.Client().Resources().List(ctx, nodes); err != nil { + t.Fatal("cannot list nodes", err) + } + if len(nodes.Items) == 0 { + t.Fatalf("no nodes in the cluster") + } + i := slices.IndexFunc(nodes.Items[0].Status.Addresses, func(a corev1.NodeAddress) bool { + return a.Type == corev1.NodeInternalIP + }) + if i == -1 { + t.Fatalf("no nodes with private address") + } + addr := nodes.Items[0].Status.Addresses[i].Address + p := gexe.RunProc(fmt.Sprintf("skopeo copy docker-daemon:crossplane-e2e/fn-labelizer:latest docker://%s:32000/fn-labelizer:latest --dest-tls-verify=false", addr)).Wait() + out, _ := io.ReadAll(p.Out()) + t.Logf("skopeo stdout: %s", string(out)) if p.ExitCode() != 0 { - out, _ := io.ReadAll(p.Out()) t.Fatalf("copying image to registry not successful, exit code %v std out %v std err %v", p.ExitCode(), string(out), p.Err()) } return ctx @@ -236,7 +250,10 @@ func CrossplaneDeployedWithFunctionsEnabled() features.Func { "--set xfn.args={--debug}", "--set registryCaBundleConfig.name=reg-ca", "--set registryCaBundleConfig.key=domain.crt", - ))...)), + "--set xfn.resources.requests.cpu=100m", + "--set xfn.resources.limits.cpu=100m", + ), + helm.WithWait())...)), funcs.ReadyToTestWithin(1*time.Minute, namespace), ) } From dcaeba1f4c659c1928e7e5193f29e4d2c86e41bf Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Mon, 3 Jul 2023 15:25:50 +0200 Subject: [PATCH 034/148] Addressed reviewers comments Signed-off-by: Predrag Knezevic --- go.mod | 4 +- go.sum | 2 - test/e2e/funcs/feature.go | 11 --- .../private-registry/pull}/claim.yaml | 0 .../private-registry/pull}/composition.yaml | 0 .../pull/prerequisites/definition.yaml | 29 ++++++++ .../pull/prerequisites/provider.yaml | 7 ++ test/e2e/xfn_test.go | 74 +++++++++++-------- 8 files changed, 82 insertions(+), 45 deletions(-) rename test/e2e/manifests/{apiextensions/composition/functions/private-registry => xfnrunner/private-registry/pull}/claim.yaml (100%) rename test/e2e/manifests/{apiextensions/composition/functions/private-registry => xfnrunner/private-registry/pull}/composition.yaml (100%) create mode 100644 test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/definition.yaml create mode 100644 test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/provider.yaml diff --git a/go.mod b/go.mod index a42f658b1..2ab14207d 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 + github.com/vladimirvivien/gexe v0.2.0 golang.org/x/sync v0.3.0 golang.org/x/sys v0.10.0 google.golang.org/grpc v1.56.1 @@ -37,8 +38,6 @@ require ( sigs.k8s.io/yaml v1.3.0 ) -require golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df - require ( cloud.google.com/go/compute v1.19.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect @@ -156,7 +155,6 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/tetratelabs/wazero v1.2.1 // indirect github.com/vbatts/tar-split v0.11.3 // indirect - github.com/vladimirvivien/gexe v0.2.0 go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect diff --git a/go.sum b/go.sum index 7b13bccb0..f192a73ee 100644 --- a/go.sum +++ b/go.sum @@ -558,8 +558,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index e3658144b..1a942f05d 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -385,17 +385,6 @@ func DeleteResources(dir, pattern string) features.Func { } } -// CreateNamespace creates the given namespace -func CreateNamespace(name string) features.Func { - return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: name}} - if err := config.Client().Resources().Create(ctx, ns); err != nil { - t.Fatalf(fmt.Sprintf("error creating namespace %s", name), err) - } - return ctx - } -} - // asUnstructured turns an arbitrary runtime.Object into an *Unstructured. If // it's already a concrete *Unstructured it just returns it, otherwise it // round-trips it through JSON encoding. This is necessary because types that diff --git a/test/e2e/manifests/apiextensions/composition/functions/private-registry/claim.yaml b/test/e2e/manifests/xfnrunner/private-registry/pull/claim.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/functions/private-registry/claim.yaml rename to test/e2e/manifests/xfnrunner/private-registry/pull/claim.yaml diff --git a/test/e2e/manifests/apiextensions/composition/functions/private-registry/composition.yaml b/test/e2e/manifests/xfnrunner/private-registry/pull/composition.yaml similarity index 100% rename from test/e2e/manifests/apiextensions/composition/functions/private-registry/composition.yaml rename to test/e2e/manifests/xfnrunner/private-registry/pull/composition.yaml diff --git a/test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/definition.yaml b/test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/definition.yaml new file mode 100644 index 000000000..bf70cb798 --- /dev/null +++ b/test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/definition.yaml @@ -0,0 +1,29 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: CompositeResourceDefinition +metadata: + name: xnopresources.nop.example.org +spec: + group: nop.example.org + names: + kind: XNopResource + plural: xnopresources + claimNames: + kind: NopResource + plural: nopresources + connectionSecretKeys: + - test + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + coolField: + type: string + required: + - coolField \ No newline at end of file diff --git a/test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/provider.yaml b/test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/provider.yaml new file mode 100644 index 000000000..2f8d0708f --- /dev/null +++ b/test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites/provider.yaml @@ -0,0 +1,7 @@ +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-nop +spec: + package: xpkg.upbound.io/crossplane-contrib/provider-nop:v0.2.0 + ignoreCrossplaneConstraints: true \ No newline at end of file diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index f64aef95d..3103a62d2 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -30,14 +30,14 @@ import ( "time" "github.com/vladimirvivien/gexe" - "golang.org/x/exp/slices" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" - client2 "sigs.k8s.io/controller-runtime/pkg/client" + cr "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/e2e-framework/klient/wait" "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" "sigs.k8s.io/e2e-framework/pkg/features" "sigs.k8s.io/e2e-framework/third_party/helm" @@ -47,18 +47,21 @@ import ( "github.com/crossplane/crossplane/test/e2e/funcs" ) -func TestFunctions(t *testing.T) { +func TestXfnRunnerImagePull(t *testing.T) { - manifests := "test/e2e/manifests/apiextensions/composition/functions/private-registry" + manifests := "test/e2e/manifests/xfnrunner/private-registry/pull" environment.Test(t, - features.New("PullImageFromPrivateRegistryWithCustomCert"). + features.New("PullFnImageFromPrivateRegistryWithCustomCert"). WithLabel(LabelArea, "xfn"). - Setup(funcs.CreateNamespace("reg")). - Setup(CreateTLSCertificateAsSecret("private-docker-registry.reg.svc.cluster.local", "reg")). - Setup(InstallDockerRegistry()). - Setup(CopyImagesToRegistry()). - Setup(CrossplaneDeployedWithFunctionsEnabled()). - Setup(ProvideNopDeployed()). + WithSetup("InstallRegistryWithCustomTlsCertificate", + funcs.AllOf( + funcs.AsFeaturesFunc(envfuncs.CreateNamespace("reg")), + CreateTLSCertificateAsSecret("private-docker-registry.reg.svc.cluster.local", "reg"), + InstallDockerRegistry(), + )). + WithSetup("CopyFnImageToRegistry", CopyImagesToRegistry()). + WithSetup("CrossplaneDeployedWithFunctionsEnabled", CrossplaneDeployedWithFunctionsEnabled()). + WithSetup("ProvideNopDeployed", ProvideNopDeployed()). Assess("CompositionWithFunctionIsCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "composition.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "composition.yaml"), @@ -82,7 +85,7 @@ func resourceGetter(ctx context.Context, t *testing.T, config *envconf.Config) f t.Fatal(err) } u.SetGroupVersionKind(gv.WithKind(kind)) - if err := client.Get(ctx, client2.ObjectKey{Name: name, Namespace: namespace}, u); err != nil { + if err := client.Get(ctx, cr.ObjectKey{Name: name, Namespace: namespace}, u); err != nil { t.Fatal("cannot get claim", err) } return u @@ -207,13 +210,17 @@ func CopyImagesToRegistry() features.Func { if len(nodes.Items) == 0 { t.Fatalf("no nodes in the cluster") } - i := slices.IndexFunc(nodes.Items[0].Status.Addresses, func(a corev1.NodeAddress) bool { - return a.Type == corev1.NodeInternalIP - }) - if i == -1 { + var addr string + for _, a := range nodes.Items[0].Status.Addresses { + if a.Type == corev1.NodeInternalIP { + addr = a.Address + break + } + } + if addr == "" { t.Fatalf("no nodes with private address") } - addr := nodes.Items[0].Status.Addresses[i].Address + p := gexe.RunProc(fmt.Sprintf("skopeo copy docker-daemon:crossplane-e2e/fn-labelizer:latest docker://%s:32000/fn-labelizer:latest --dest-tls-verify=false", addr)).Wait() out, _ := io.ReadAll(p.Out()) t.Logf("skopeo stdout: %s", string(out)) @@ -226,17 +233,26 @@ func CopyImagesToRegistry() features.Func { // InstallDockerRegistry with custom TLS func InstallDockerRegistry() features.Func { - return funcs.AsFeaturesFunc(funcs.HelmInstall( - helm.WithName("private"), - helm.WithNamespace("reg"), - helm.WithWait(), - helm.WithChart("https://helm.twun.io/docker-registry-2.2.1.tgz"), - helm.WithArgs( - "--set service.type=NodePort", - "--set service.nodePort=32000", - "--set tlsSecretName=reg-cert", - ), - )) + return funcs.AllOf( + funcs.AsFeaturesFunc( + funcs.HelmRepo( + helm.WithArgs("add"), + helm.WithArgs("twuni"), + helm.WithArgs("https://helm.twun.io"), + )), + funcs.AsFeaturesFunc( + funcs.HelmInstall( + helm.WithName("private"), + helm.WithNamespace("reg"), + helm.WithWait(), + helm.WithChart("twuni/docker-registry"), + helm.WithVersion("2.2.2"), + helm.WithArgs( + "--set service.type=NodePort", + "--set service.nodePort=32000", + "--set tlsSecretName=reg-cert", + ), + ))) } // CrossplaneDeployedWithFunctionsEnabled asserts that crossplane deployment with composition functions is enabled @@ -260,7 +276,7 @@ func CrossplaneDeployedWithFunctionsEnabled() features.Func { // ProvideNopDeployed assets that provider-nop is deployed and healthy func ProvideNopDeployed() features.Func { - manifests := "test/e2e/manifests/apiextensions/composition/minimal/prerequisites" + manifests := "test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites" return funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "provider.yaml"), funcs.ApplyResources(FieldManager, manifests, "definition.yaml"), From 88d7a2c9a9109e4cd0cc641f4c7959e67c161bb5 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Mon, 3 Jul 2023 17:48:29 +0200 Subject: [PATCH 035/148] replace skopeo with direct usage of go-containerregistry library Signed-off-by: Predrag Knezevic --- go.mod | 2 +- test/e2e/xfn_test.go | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 2ab14207d..12e945856 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,6 @@ require ( github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 - github.com/vladimirvivien/gexe v0.2.0 golang.org/x/sync v0.3.0 golang.org/x/sys v0.10.0 google.golang.org/grpc v1.56.1 @@ -155,6 +154,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/tetratelabs/wazero v1.2.1 // indirect github.com/vbatts/tar-split v0.11.3 // indirect + github.com/vladimirvivien/gexe v0.2.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/sdk v1.16.0 // indirect diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 3103a62d2..0a42e4041 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -23,13 +23,14 @@ import ( "crypto/x509/pkix" "encoding/pem" "fmt" - "io" "math/big" "reflect" "testing" "time" - "github.com/vladimirvivien/gexe" + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/daemon" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -221,11 +222,18 @@ func CopyImagesToRegistry() features.Func { t.Fatalf("no nodes with private address") } - p := gexe.RunProc(fmt.Sprintf("skopeo copy docker-daemon:crossplane-e2e/fn-labelizer:latest docker://%s:32000/fn-labelizer:latest --dest-tls-verify=false", addr)).Wait() - out, _ := io.ReadAll(p.Out()) - t.Logf("skopeo stdout: %s", string(out)) - if p.ExitCode() != 0 { - t.Fatalf("copying image to registry not successful, exit code %v std out %v std err %v", p.ExitCode(), string(out), p.Err()) + srcRef, err := name.ParseReference("crossplane-e2e/fn-labelizer:latest") + if err != nil { + t.Fatal(err) + } + src, err := daemon.Image(srcRef) + if err != nil { + t.Fatal(err) + } + + err = crane.Push(src, fmt.Sprintf("%s:32000/fn-labelizer:latest", addr), crane.Insecure) + if err != nil { + t.Fatal("copying image to registry not successful", err) } return ctx } From adfa6412ba5e25d41e37fabb832e5d93465e90b5 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Tue, 4 Jul 2023 14:56:35 +0200 Subject: [PATCH 036/148] added unit test for WithCustomCA Signed-off-by: Predrag Knezevic --- Makefile | 2 ++ internal/oci/pull_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Makefile b/Makefile index 0ec7adc25..dd63433a8 100644 --- a/Makefile +++ b/Makefile @@ -116,6 +116,8 @@ cobertura: grep -v zz_generated.deepcopy | \ $(GOCOVER_COBERTURA) > $(GO_TEST_OUTPUT)/cobertura-coverage.xml +# TODO(pedjak): +# https://github.com/crossplane/crossplane/issues/4294 e2e.test.images: @$(INFO) Building E2E test images @docker build --load -t $(BUILD_REGISTRY)/fn-labelizer-$(TARGETARCH) test/e2e/testdata/images/labelizer diff --git a/internal/oci/pull_test.go b/internal/oci/pull_test.go index 96a0ccd07..1580e11ad 100644 --- a/internal/oci/pull_test.go +++ b/internal/oci/pull_test.go @@ -18,6 +18,7 @@ package oci import ( "context" + "crypto/x509" "testing" "github.com/google/go-cmp/cmp" @@ -298,6 +299,44 @@ func TestImage(t *testing.T) { i: &MockImage{}, }, }, + "PullWithCustomCA": { + reason: "We should return a pulled and cached image.", + p: NewCachingPuller( + &MockHashCache{ + MockHash: func(r name.Reference) (ociv1.Hash, error) { + return ociv1.Hash{}, errors.New("this error should not be returned") + }, + MockWriteHash: func(r name.Reference, h ociv1.Hash) error { + return nil + }, + }, + &MockImageCache{ + MockWriteImage: func(img ociv1.Image) error { return nil }, + MockImage: func(h ociv1.Hash) (ociv1.Image, error) { return &MockImage{}, nil }, + }, + &MockImageClient{ + MockImage: func(ctx context.Context, ref name.Reference, o ...ImageClientOption) (ociv1.Image, error) { + if len(o) != 1 { + return nil, errors.New("the number of options should be one") + } + c := &ImageClientOptions{} + o[0](c) + if c.transport == nil { + return nil, errors.New("Transport should be set") + } + return &MockImage{ + MockDigest: func() (ociv1.Hash, error) { return ociv1.Hash{}, nil }, + }, nil + }, + }, + ), + args: args{ + o: []ImageClientOption{WithCustomCA(&x509.CertPool{})}, + }, + want: want{ + i: &MockImage{}, + }, + }, "IfNotPresentTriesCacheFirst": { reason: "The IfNotPresent policy should try to read from cache first.", p: NewCachingPuller( From 1a558c13cda23c1e76357e945eabd3ce61b9c454 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:15:33 +0000 Subject: [PATCH 037/148] Update github/codeql-action digest to 46ed16d --- .github/workflows/ci.yml | 4 ++-- .github/workflows/scan.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d14831161..313435bf4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,12 @@ jobs: run: make vendor vendor.check - name: Initialize CodeQL - uses: github/codeql-action/init@004c5de30b6423267685b897a3d595e944f7fed5 # v2 + uses: github/codeql-action/init@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@004c5de30b6423267685b897a3d595e944f7fed5 # v2 + uses: github/codeql-action/analyze@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2 trivy-scan-fs: runs-on: ubuntu-22.04 diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml index 7e8912a3f..26b6e2fbb 100644 --- a/.github/workflows/scan.yaml +++ b/.github/workflows/scan.yaml @@ -131,7 +131,7 @@ jobs: retention-days: 3 - name: Upload Trivy Scan Results To GitHub Security Tab - uses: github/codeql-action/upload-sarif@004c5de30b6423267685b897a3d595e944f7fed5 # v2 + uses: github/codeql-action/upload-sarif@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2 with: sarif_file: 'trivy-results.sarif' category: ${{ matrix.image }}:${{ env.tag }} From 258747fbe7fd7797ac4abc14b046779cdc6626fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 19:13:51 +0000 Subject: [PATCH 038/148] Update module google.golang.org/grpc to v1.56.2 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 12e945856..ea2f3bb28 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spf13/afero v1.9.5 golang.org/x/sync v0.3.0 golang.org/x/sys v0.10.0 - google.golang.org/grpc v1.56.1 + google.golang.org/grpc v1.56.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/protobuf v1.31.0 k8s.io/api v0.27.3 diff --git a/go.sum b/go.sum index f192a73ee..47a6cd29a 100644 --- a/go.sum +++ b/go.sum @@ -881,8 +881,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ= -google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= From f440ce73eb9e0c240274754659d70902454de495 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:31:35 +0000 Subject: [PATCH 039/148] Update docker/setup-buildx-action digest to 2a1a44a --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 313435bf4..ac073bc0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -249,7 +249,7 @@ jobs: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2 + uses: docker/setup-buildx-action@2a1a44ac4aa01993040736bd95bb470da1a38365 # v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true @@ -311,7 +311,7 @@ jobs: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@16c0bc4a6e6ada2cfd8afd41d22d95379cf7c32a # v2 + uses: docker/setup-buildx-action@2a1a44ac4aa01993040736bd95bb470da1a38365 # v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true From 8435206d49e24ed1007f594a9cc2b2350bf7a137 Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Fri, 7 Jul 2023 18:10:03 +0300 Subject: [PATCH 040/148] Change /tmp folders permissions to allow write access Signed-off-by: ezgidemirel --- internal/oci/spec/spec.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/oci/spec/spec.go b/internal/oci/spec/spec.go index 3331c8b04..843a71c31 100644 --- a/internal/oci/spec/spec.go +++ b/internal/oci/spec/spec.go @@ -110,6 +110,12 @@ func New(o ...Option) (*runtime.Spec, error) { Source: "tmpfs", Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, }, + { + Type: "tmpfs", + Destination: "/tmp", + Source: "tmp", + Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, + }, { Type: "bind", Destination: "/sys", From f15b4cff3edddc3a0abf19132d4f33eb019abc0f Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Mon, 10 Jul 2023 17:40:33 +0200 Subject: [PATCH 041/148] restructured xfn_test.go to match style of other files under test/e2e * unwrapped all setup func * in order to keep the style aligned with other test files, cert and resource getter functions moved test/e2e/utils package * made them public, although its reusage in other cases is still questionable Signed-off-by: Predrag Knezevic --- test/e2e/utils/cert.go | 84 +++++++ test/e2e/utils/resources.go | 102 +++++++++ test/e2e/utils/utils.go | 19 ++ test/e2e/xfn_test.go | 424 ++++++++++++------------------------ 4 files changed, 346 insertions(+), 283 deletions(-) create mode 100644 test/e2e/utils/cert.go create mode 100644 test/e2e/utils/resources.go create mode 100644 test/e2e/utils/utils.go diff --git a/test/e2e/utils/cert.go b/test/e2e/utils/cert.go new file mode 100644 index 000000000..d327fe80c --- /dev/null +++ b/test/e2e/utils/cert.go @@ -0,0 +1,84 @@ +/* +Copyright 2023 The Crossplane Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "time" +) + +// CreateCert create TLS certificate for given dns name +// and returns CA and key in PEM format, or an error +func CreateCert(dnsName string) (string, string, error) { + ca := &x509.Certificate{ + SerialNumber: big.NewInt(2019), + Subject: pkix.Name{ + Organization: []string{"Company, INC."}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{""}, + StreetAddress: []string{""}, + PostalCode: []string{""}, + CommonName: dnsName, + }, + DNSNames: []string{dnsName}, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + // create our private and public key + caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return "", "", err + } + + // create the CA + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) + if err != nil { + return "", "", err + } + + // pem encode + caPEM := new(bytes.Buffer) + err = pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }) + if err != nil { + return "", "", err + } + + keyPEM := new(bytes.Buffer) + err = pem.Encode(keyPEM, &pem.Block{ + Type: "PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), + }) + if err != nil { + return "", "", err + } + + return caPEM.String(), keyPEM.String(), nil +} diff --git a/test/e2e/utils/resources.go b/test/e2e/utils/resources.go new file mode 100644 index 000000000..2e7a4ef2e --- /dev/null +++ b/test/e2e/utils/resources.go @@ -0,0 +1,102 @@ +/* +Copyright 2023 The Crossplane Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "context" + "fmt" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + cr "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/e2e-framework/pkg/envconf" +) + +// ResourceGetter retrieves arbitrary k8s objects +type ResourceGetter struct { + ctx context.Context + t *testing.T + config *envconf.Config +} + +// NewResourceGetter returns a new getter that can be used for retrieving k8s objects of arbitrary type +func NewResourceGetter(ctx context.Context, t *testing.T, config *envconf.Config) *ResourceGetter { + return &ResourceGetter{ + ctx: ctx, + t: t, + config: config, + } +} + +// Get returns k8s object for the given name, namespace, apiVersion and kind +// if the requested object does not exist, the test fails +func (r *ResourceGetter) Get(name string, namespace string, apiVersion string, kind string) *unstructured.Unstructured { + client := r.config.Client().Resources().GetControllerRuntimeClient() + u := &unstructured.Unstructured{} + gv, err := schema.ParseGroupVersion(apiVersion) + if err != nil { + r.t.Fatal(err) + } + u.SetGroupVersionKind(gv.WithKind(kind)) + if err := client.Get(r.ctx, cr.ObjectKey{Name: name, Namespace: namespace}, u); err != nil { + r.t.Fatal("cannot get claim", err) + } + return u +} + +// ResourceValue returns the value of field on the given path +// in case of error or if the field does not exist, the test fails +func ResourceValue(t *testing.T, u *unstructured.Unstructured, path ...string) map[string]string { + f, found, err := unstructured.NestedStringMap(u.Object, path...) + if err != nil { + t.Fatal(err) + } + if !found { + t.Fatalf("field not found at path %v", path) + } + return f +} + +// ResourceSliceValue returns the slice value of field on the given path +// in case of error or if the field does not exist, the test fails +func ResourceSliceValue(t *testing.T, u *unstructured.Unstructured, path ...string) []map[string]string { + f, found, err := unstructured.NestedSlice(u.Object, path...) + if err != nil { + t.Fatal(err) + } + if !found { + t.Fatalf("field not found at path %v", path) + } + var s []map[string]string + for _, v := range f { + if vv, ok := v.(map[string]interface{}); ok { + s = append(s, asMapOfStrings(vv)) + } else { + t.Fatalf("not a map[string]string: %v type %s", v, reflect.TypeOf(v)) + } + } + return s +} + +func asMapOfStrings(m map[string]interface{}) map[string]string { + r := make(map[string]string) + for k, v := range m { + r[k] = fmt.Sprintf("%v", v) + } + return r +} diff --git a/test/e2e/utils/utils.go b/test/e2e/utils/utils.go new file mode 100644 index 000000000..6112fd515 --- /dev/null +++ b/test/e2e/utils/utils.go @@ -0,0 +1,19 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package utils contains convenience functions for certification creations +// and for retrieving k8s objects and their field values +package utils diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 0a42e4041..0e5c82ec9 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -15,16 +15,8 @@ limitations under the License. package e2e import ( - "bytes" "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" "fmt" - "math/big" - "reflect" "testing" "time" @@ -33,9 +25,6 @@ import ( "github.com/google/go-containerregistry/pkg/v1/daemon" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - cr "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/e2e-framework/klient/wait" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" @@ -46,6 +35,7 @@ import ( v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" "github.com/crossplane/crossplane/test/e2e/funcs" + "github.com/crossplane/crossplane/test/e2e/utils" ) func TestXfnRunnerImagePull(t *testing.T) { @@ -57,12 +47,120 @@ func TestXfnRunnerImagePull(t *testing.T) { WithSetup("InstallRegistryWithCustomTlsCertificate", funcs.AllOf( funcs.AsFeaturesFunc(envfuncs.CreateNamespace("reg")), - CreateTLSCertificateAsSecret("private-docker-registry.reg.svc.cluster.local", "reg"), - InstallDockerRegistry(), - )). - WithSetup("CopyFnImageToRegistry", CopyImagesToRegistry()). - WithSetup("CrossplaneDeployedWithFunctionsEnabled", CrossplaneDeployedWithFunctionsEnabled()). - WithSetup("ProvideNopDeployed", ProvideNopDeployed()). + func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + dnsName := "private-docker-registry.reg.svc.cluster.local" + ns := "reg" + caPem, keyPem, err := utils.CreateCert(dnsName) + if err != nil { + t.Fatal(err) + } + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reg-cert", + Namespace: ns, + }, + Type: corev1.SecretTypeTLS, + StringData: map[string]string{ + "tls.crt": caPem, + "tls.key": keyPem, + }, + } + client := config.Client().Resources() + if err := client.Create(ctx, secret); err != nil { + t.Fatalf("Cannot create secret %s: %v", secret.Name, err) + } + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reg-ca", + Namespace: namespace, + }, + Data: map[string]string{ + "domain.crt": caPem, + }, + } + if err := client.Create(ctx, configMap); err != nil { + t.Fatalf("Cannot create config %s: %v", configMap.Name, err) + } + return ctx + }, + + funcs.AsFeaturesFunc( + funcs.HelmRepo( + helm.WithArgs("add"), + helm.WithArgs("twuni"), + helm.WithArgs("https://helm.twun.io"), + )), + funcs.AsFeaturesFunc( + funcs.HelmInstall( + helm.WithName("private"), + helm.WithNamespace("reg"), + helm.WithWait(), + helm.WithChart("twuni/docker-registry"), + helm.WithVersion("2.2.2"), + helm.WithArgs( + "--set service.type=NodePort", + "--set service.nodePort=32000", + "--set tlsSecretName=reg-cert", + ), + ))), + ). + WithSetup("CopyFnImageToRegistry", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + nodes := &corev1.NodeList{} + if err := config.Client().Resources().List(ctx, nodes); err != nil { + t.Fatal("cannot list nodes", err) + } + if len(nodes.Items) == 0 { + t.Fatalf("no nodes in the cluster") + } + var addr string + for _, a := range nodes.Items[0].Status.Addresses { + if a.Type == corev1.NodeInternalIP { + addr = a.Address + break + } + } + if addr == "" { + t.Fatalf("no nodes with private address") + } + + srcRef, err := name.ParseReference("crossplane-e2e/fn-labelizer:latest") + if err != nil { + t.Fatal(err) + } + src, err := daemon.Image(srcRef) + if err != nil { + t.Fatal(err) + } + + err = crane.Push(src, fmt.Sprintf("%s:32000/fn-labelizer:latest", addr), crane.Insecure) + if err != nil { + t.Fatal("copying image to registry not successful", err) + } + return ctx + }). + WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade( + HelmOptions( + helm.WithArgs( + "--set args={--debug,--enable-composition-functions}", + "--set xfn.enabled=true", + "--set xfn.args={--debug}", + "--set registryCaBundleConfig.name=reg-ca", + "--set registryCaBundleConfig.key=domain.crt", + "--set xfn.resources.requests.cpu=100m", + "--set xfn.resources.limits.cpu=100m", + ), + helm.WithWait())...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). + WithSetup("ProviderNopDeployed", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "prerequisites/provider.yaml"), + funcs.ApplyResources(FieldManager, manifests, "prerequisites/definition.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/ definition.yaml", v1.WatchingComposite()), + )). Assess("CompositionWithFunctionIsCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "composition.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "composition.yaml"), @@ -72,273 +170,33 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). - Assess("ManagedResourcesProcessedByFunction", ManagedResourcedProcessedByFunction()). - Feature(), - ) -} - -func resourceGetter(ctx context.Context, t *testing.T, config *envconf.Config) func(string, string, string, string) *unstructured.Unstructured { - return func(name string, namespace string, apiVersion string, kind string) *unstructured.Unstructured { - client := config.Client().Resources().GetControllerRuntimeClient() - u := &unstructured.Unstructured{} - gv, err := schema.ParseGroupVersion(apiVersion) - if err != nil { - t.Fatal(err) - } - u.SetGroupVersionKind(gv.WithKind(kind)) - if err := client.Get(ctx, cr.ObjectKey{Name: name, Namespace: namespace}, u); err != nil { - t.Fatal("cannot get claim", err) - } - return u - } -} -func resourceValue(t *testing.T, u *unstructured.Unstructured, path ...string) map[string]string { - f, found, err := unstructured.NestedStringMap(u.Object, path...) - if err != nil { - t.Fatal(err) - } - if !found { - t.Fatalf("field not found at path %v", path) - } - return f -} - -func resourceSliceValue(t *testing.T, u *unstructured.Unstructured, path ...string) []map[string]string { - f, found, err := unstructured.NestedSlice(u.Object, path...) - if err != nil { - t.Fatal(err) - } - if !found { - t.Fatalf("field not found at path %v", path) - } - var s []map[string]string - for _, v := range f { - if vv, ok := v.(map[string]interface{}); ok { - s = append(s, asMapOfStrings(vv)) - } else { - t.Fatalf("not a map[string]string: %v type %s", v, reflect.TypeOf(v)) - } - } - return s -} - -func asMapOfStrings(m map[string]interface{}) map[string]string { - r := make(map[string]string) - for k, v := range m { - r[k] = fmt.Sprintf("%v", v) - } - return r -} + Assess("ManagedResourcesProcessedByFunction", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + labelName := "labelizer.xfn.crossplane.io/processed" + rg := utils.NewResourceGetter(ctx, t, config) + claim := rg.Get("fn-labelizer", "default", "nop.example.org/v1alpha1", "NopResource") + r := utils.ResourceValue(t, claim, "spec", "resourceRef") + + xr := rg.Get(r["name"], "default", r["apiVersion"], r["kind"]) + mrefs := utils.ResourceSliceValue(t, xr, "spec", "resourceRefs") + for _, mref := range mrefs { + err := wait.For(func() (done bool, err error) { + mr := rg.Get(mref["name"], "default", mref["apiVersion"], mref["kind"]) + l, found := mr.GetLabels()[labelName] + if !found { + return false, nil + } + if l != "true" { + return false, nil + } + return true, nil + }, wait.WithTimeout(5*time.Minute)) + if err != nil { + t.Fatalf("Expected label %v value to be true", labelName) + } -// ManagedResourcedProcessedByFunction asserts that MRs contains the requested label -func ManagedResourcedProcessedByFunction() features.Func { - - return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - labelName := "labelizer.xfn.crossplane.io/processed" - rg := resourceGetter(ctx, t, config) - claim := rg("fn-labelizer", "default", "nop.example.org/v1alpha1", "NopResource") - r := resourceValue(t, claim, "spec", "resourceRef") - - xr := rg(r["name"], "default", r["apiVersion"], r["kind"]) - mrefs := resourceSliceValue(t, xr, "spec", "resourceRefs") - for _, mref := range mrefs { - err := wait.For(func() (done bool, err error) { - mr := rg(mref["name"], "default", mref["apiVersion"], mref["kind"]) - l, found := mr.GetLabels()[labelName] - if !found { - return false, nil - } - if l != "true" { - return false, nil } - return true, nil - }, wait.WithTimeout(5*time.Minute)) - if err != nil { - t.Fatalf("Expected label %v value to be true", labelName) - } - - } - return ctx - } -} - -// CreateTLSCertificateAsSecret for given dns name and store the secret in the given namespace -func CreateTLSCertificateAsSecret(dnsName string, ns string) features.Func { - return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - caPem, keyPem, err := createCert(dnsName) - if err != nil { - t.Fatal(err) - } - - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "reg-cert", - Namespace: ns, - }, - Type: corev1.SecretTypeTLS, - StringData: map[string]string{ - "tls.crt": caPem, - "tls.key": keyPem, - }, - } - client := config.Client().Resources() - if err := client.Create(ctx, secret); err != nil { - t.Fatalf("Cannot create secret %s: %v", secret.Name, err) - } - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "reg-ca", - Namespace: namespace, - }, - Data: map[string]string{ - "domain.crt": caPem, - }, - } - if err := client.Create(ctx, configMap); err != nil { - t.Fatalf("Cannot create config %s: %v", configMap.Name, err) - } - return ctx - } -} - -// CopyImagesToRegistry copies fn images to private registry -func CopyImagesToRegistry() features.Func { - return func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - nodes := &corev1.NodeList{} - if err := config.Client().Resources().List(ctx, nodes); err != nil { - t.Fatal("cannot list nodes", err) - } - if len(nodes.Items) == 0 { - t.Fatalf("no nodes in the cluster") - } - var addr string - for _, a := range nodes.Items[0].Status.Addresses { - if a.Type == corev1.NodeInternalIP { - addr = a.Address - break - } - } - if addr == "" { - t.Fatalf("no nodes with private address") - } - - srcRef, err := name.ParseReference("crossplane-e2e/fn-labelizer:latest") - if err != nil { - t.Fatal(err) - } - src, err := daemon.Image(srcRef) - if err != nil { - t.Fatal(err) - } - - err = crane.Push(src, fmt.Sprintf("%s:32000/fn-labelizer:latest", addr), crane.Insecure) - if err != nil { - t.Fatal("copying image to registry not successful", err) - } - return ctx - } -} - -// InstallDockerRegistry with custom TLS -func InstallDockerRegistry() features.Func { - return funcs.AllOf( - funcs.AsFeaturesFunc( - funcs.HelmRepo( - helm.WithArgs("add"), - helm.WithArgs("twuni"), - helm.WithArgs("https://helm.twun.io"), - )), - funcs.AsFeaturesFunc( - funcs.HelmInstall( - helm.WithName("private"), - helm.WithNamespace("reg"), - helm.WithWait(), - helm.WithChart("twuni/docker-registry"), - helm.WithVersion("2.2.2"), - helm.WithArgs( - "--set service.type=NodePort", - "--set service.nodePort=32000", - "--set tlsSecretName=reg-cert", - ), - ))) -} - -// CrossplaneDeployedWithFunctionsEnabled asserts that crossplane deployment with composition functions is enabled -func CrossplaneDeployedWithFunctionsEnabled() features.Func { - return funcs.AllOf( - funcs.AsFeaturesFunc(funcs.HelmUpgrade( - HelmOptions( - helm.WithArgs( - "--set args={--debug,--enable-composition-functions}", - "--set xfn.enabled=true", - "--set xfn.args={--debug}", - "--set registryCaBundleConfig.name=reg-ca", - "--set registryCaBundleConfig.key=domain.crt", - "--set xfn.resources.requests.cpu=100m", - "--set xfn.resources.limits.cpu=100m", - ), - helm.WithWait())...)), - funcs.ReadyToTestWithin(1*time.Minute, namespace), - ) -} - -// ProvideNopDeployed assets that provider-nop is deployed and healthy -func ProvideNopDeployed() features.Func { - manifests := "test/e2e/manifests/xfnrunner/private-registry/pull/prerequisites" - return funcs.AllOf( - funcs.ApplyResources(FieldManager, manifests, "provider.yaml"), - funcs.ApplyResources(FieldManager, manifests, "definition.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "provider.yaml"), - funcs.ResourcesCreatedWithin(30*time.Second, manifests, "definition.yaml"), - funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "definition.yaml", v1.WatchingComposite()), + return ctx + }). + Feature(), ) } - -func createCert(dnsName string) (string, string, error) { - ca := &x509.Certificate{ - SerialNumber: big.NewInt(2019), - Subject: pkix.Name{ - Organization: []string{"Company, INC."}, - Country: []string{"US"}, - Province: []string{""}, - Locality: []string{""}, - StreetAddress: []string{""}, - PostalCode: []string{""}, - CommonName: dnsName, - }, - DNSNames: []string{dnsName}, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), - IsCA: true, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - - // create our private and public key - caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) - if err != nil { - return "", "", err - } - - // create the CA - caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) - if err != nil { - return "", "", err - } - - // pem encode - caPEM := new(bytes.Buffer) - pem.Encode(caPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: caBytes, - }) - - keyPEM := new(bytes.Buffer) - pem.Encode(keyPEM, &pem.Block{ - Type: "PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), - }) - - return caPEM.String(), keyPEM.String(), nil -} From c29524c7171f00ad07d4dfcb7e85db5c81de43b1 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Mon, 10 Jul 2023 18:26:03 +0200 Subject: [PATCH 042/148] retry copying images if registry was not ready Signed-off-by: Predrag Knezevic --- test/e2e/xfn_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 0e5c82ec9..9db346d00 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -132,8 +132,13 @@ func TestXfnRunnerImagePull(t *testing.T) { if err != nil { t.Fatal(err) } - - err = crane.Push(src, fmt.Sprintf("%s:32000/fn-labelizer:latest", addr), crane.Insecure) + err = wait.For(func() (done bool, err error) { + err = crane.Push(src, fmt.Sprintf("%s:32000/fn-labelizer:latest", addr), crane.Insecure) + if err != nil { + return false, nil //nolint:nilerr // we want to retry and to throw error + } + return true, nil + }, wait.WithTimeout(1*time.Minute)) if err != nil { t.Fatal("copying image to registry not successful", err) } @@ -159,7 +164,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "prerequisites/definition.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), - funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/ definition.yaml", v1.WatchingComposite()), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", v1.WatchingComposite()), )). Assess("CompositionWithFunctionIsCreated", funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, "composition.yaml"), From 9b22c2265a4ef5a1390071d997a2f33bd6d842ba Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 08:59:55 +0200 Subject: [PATCH 043/148] guide-observability.md: don't record events on noops Signed-off-by: Dr. Stefan Schimanski --- contributing/guide-observability.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contributing/guide-observability.md b/contributing/guide-observability.md index 9343d0bc7..c27a0647a 100644 --- a/contributing/guide-observability.md +++ b/contributing/guide-observability.md @@ -50,6 +50,9 @@ Events should be recorded in the following cases: * The state of a resource is changed * An error occurs +Events should *not* be recorded if nothing happens or changes, with the exception +of repeated errors. + The events recorded in these cases can be thought of as forming an event log of things that happen for the resources that Crossplane manages. Each event should refer back to the relevant controller and resource, and use other fields of the From 0e92bf08896c3d077c81916e599888e14f48f1d8 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Tue, 11 Jul 2023 11:11:14 +0200 Subject: [PATCH 044/148] added missing teardown Signed-off-by: Predrag Knezevic --- test/e2e/xfn_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 9db346d00..b847a35c5 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -202,6 +202,41 @@ func TestXfnRunnerImagePull(t *testing.T) { } return ctx }). + WithTeardown("DeleteClaim", funcs.AllOf( + funcs.DeleteResources(manifests, "claim.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), + )). + WithTeardown("DeleteComposition", funcs.AllOf( + funcs.DeleteResources(manifests, "composition.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "composition.yaml"), + )). + WithTeardown("ProviderNopRemoved", funcs.AllOf( + funcs.DeleteResources(manifests, "prerequisites/provider.yaml"), + funcs.DeleteResources(manifests, "prerequisites/definition.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), + )). + WithTeardown("RemoveRegistry", funcs.AllOf( + funcs.AsFeaturesFunc(envfuncs.DeleteNamespace("reg")), + func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + client := config.Client().Resources(namespace) + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reg-ca", + Namespace: namespace, + }, + } + err := client.Delete(ctx, configMap) + if err != nil { + t.Fatal(err) + } + return ctx + }, + )). + WithTeardown("CrossplaneDeployedWithoutFunctionsEnabled", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). Feature(), ) } From 61d2693c3b5a9de0b7d8718c425a64aad2844c11 Mon Sep 17 00:00:00 2001 From: Florian Hopfensperger Date: Tue, 11 Jul 2023 09:25:37 +0200 Subject: [PATCH 045/148] feat(xrd) add labels and annotations Signed-off-by: Florian Hopfensperger --- apis/apiextensions/v1/xrd_types.go | 23 +++ .../apiextensions/v1/zz_generated.deepcopy.go | 34 ++++ ...plane.io_compositeresourcedefinitions.yaml | 23 +++ internal/xcrd/crd.go | 25 ++- internal/xcrd/crd_test.go | 186 ++++++++++++++++++ 5 files changed, 289 insertions(+), 2 deletions(-) diff --git a/apis/apiextensions/v1/xrd_types.go b/apis/apiextensions/v1/xrd_types.go index 914ee47eb..c2ec81ceb 100644 --- a/apis/apiextensions/v1/xrd_types.go +++ b/apis/apiextensions/v1/xrd_types.go @@ -95,6 +95,10 @@ type CompositeResourceDefinitionSpec struct { // Conversion defines all conversion settings for the defined Composite resource. // +optional Conversion *extv1.CustomResourceConversion `json:"conversion,omitempty"` + + // Metadata specifies the desired metadata for the defined composite resource and claim CRD's. + // +optional + Metadata *CompositeResourceDefinitionSpecMetadata `json:"metadata,omitempty"` } // A CompositionReference references a Composition. @@ -103,6 +107,25 @@ type CompositionReference struct { Name string `json:"name"` } +// CompositeResourceDefinitionSpecMetadata specifies the desired metadata of the defined composite resource and claim CRD's. +type CompositeResourceDefinitionSpecMetadata struct { + // Map of string keys and values that can be used to organize and categorize + // (scope and select) objects. May match selectors of replication controllers + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels + // and services. + // These labels are added to the composite resource and claim CRD's in addition + // to any labels defined by `CompositionResourceDefinition` `metadata.labels`. + // +optional + Labels map[string]string `json:"labels,omitempty"` + + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations + // +optional + Annotations map[string]string `json:"annotations,omitempty"` +} + // CompositeResourceDefinitionVersion describes a version of an XR. type CompositeResourceDefinitionVersion struct { // Name of this version, e.g. “v1”, “v2beta1”, etc. Composite resources are diff --git a/apis/apiextensions/v1/zz_generated.deepcopy.go b/apis/apiextensions/v1/zz_generated.deepcopy.go index ab410c04f..80567a4b5 100644 --- a/apis/apiextensions/v1/zz_generated.deepcopy.go +++ b/apis/apiextensions/v1/zz_generated.deepcopy.go @@ -233,6 +233,11 @@ func (in *CompositeResourceDefinitionSpec) DeepCopyInto(out *CompositeResourceDe *out = new(apiextensionsv1.CustomResourceConversion) (*in).DeepCopyInto(*out) } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(CompositeResourceDefinitionSpecMetadata) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeResourceDefinitionSpec. @@ -245,6 +250,35 @@ func (in *CompositeResourceDefinitionSpec) DeepCopy() *CompositeResourceDefiniti return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CompositeResourceDefinitionSpecMetadata) DeepCopyInto(out *CompositeResourceDefinitionSpecMetadata) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CompositeResourceDefinitionSpecMetadata. +func (in *CompositeResourceDefinitionSpecMetadata) DeepCopy() *CompositeResourceDefinitionSpecMetadata { + if in == nil { + return nil + } + out := new(CompositeResourceDefinitionSpecMetadata) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CompositeResourceDefinitionStatus) DeepCopyInto(out *CompositeResourceDefinitionStatus) { *out = *in diff --git a/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml b/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml index bf44003c9..8c0ecfe33 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml @@ -248,6 +248,29 @@ spec: resource. Composite resources are served under `/apis//...`. Must match the name of the XRD (in the form `.`). type: string + metadata: + description: Metadata specifies the desired metadata for the defined + composite resource and claim CRD's. + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value map stored + with a resource that may be set by external tools to store and + retrieve arbitrary metadata. They are not queryable and should + be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used to + organize and categorize (scope and select) objects. May match + selectors of replication controllers More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels + and services. These labels are added to the composite resource + and claim CRD''s in addition to any labels defined by `CompositionResourceDefinition` + `metadata.labels`.' + type: object + type: object names: description: Names specifies the resource and kind names of the defined composite resource. diff --git a/internal/xcrd/crd.go b/internal/xcrd/crd.go index 1ca31b466..cb3e046fd 100644 --- a/internal/xcrd/crd.go +++ b/internal/xcrd/crd.go @@ -63,7 +63,7 @@ func ForCompositeResource(xrd *v1.CompositeResourceDefinition) (*extv1.CustomRes } crd.SetName(xrd.GetName()) - crd.SetLabels(xrd.GetLabels()) + setCrdMetadata(crd, xrd) crd.SetOwnerReferences([]metav1.OwnerReference{meta.AsController( meta.TypedReferenceTo(xrd, v1.CompositeResourceDefinitionGroupVersionKind), )}) @@ -136,7 +136,7 @@ func ForCompositeResourceClaim(xrd *v1.CompositeResourceDefinition) (*extv1.Cust } crd.SetName(xrd.Spec.ClaimNames.Plural + "." + xrd.Spec.Group) - crd.SetLabels(xrd.GetLabels()) + setCrdMetadata(crd, xrd) crd.SetOwnerReferences([]metav1.OwnerReference{meta.AsController( meta.TypedReferenceTo(xrd, v1.CompositeResourceDefinitionGroupVersionKind), )}) @@ -233,6 +233,27 @@ func getProps(field string, v *v1.CompositeResourceValidation) (map[string]extv1 return spec.Properties, spec.Required, nil } +// setCrdMetadata sets the labels and annotations on the CRD. +func setCrdMetadata(crd *extv1.CustomResourceDefinition, xrd *v1.CompositeResourceDefinition) *extv1.CustomResourceDefinition { + crd.SetLabels(xrd.GetLabels()) + if xrd.Spec.Metadata != nil { + if xrd.Spec.Metadata.Labels != nil { + inheritedLabels := crd.GetLabels() + if inheritedLabels == nil { + inheritedLabels = map[string]string{} + } + for k, v := range xrd.Spec.Metadata.Labels { + inheritedLabels[k] = v + } + crd.SetLabels(inheritedLabels) + } + if xrd.Spec.Metadata.Annotations != nil { + crd.SetAnnotations(xrd.Spec.Metadata.Annotations) + } + } + return crd +} + // IsEstablished is a helper function to check whether api-server is ready // to accept the instances of registered CRD. func IsEstablished(s extv1.CustomResourceDefinitionStatus) bool { diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index 7ae3bc9ec..fe17dd676 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -818,3 +818,189 @@ func TestForCompositeResourceClaim(t *testing.T) { t.Errorf("ForCompositeResourceClaim(...): -want, +got:\n%s", diff) } } + +func TestSetCrdMetadata(t *testing.T) { + type args struct { + crd *extv1.CustomResourceDefinition + xrd *v1.CompositeResourceDefinition + } + tests := []struct { + name string + args args + want *extv1.CustomResourceDefinition + }{ + { + name: "set crd annotations", + args: args{ + crd: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + xrd: &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{ + "example.com/some-xrd-annotation": "not-propagated", + }, + }, + Spec: v1.CompositeResourceDefinitionSpec{Metadata: &v1.CompositeResourceDefinitionSpecMetadata{ + Annotations: map[string]string{ + "cert-manager.io/inject-ca-from": "example1-ns/webhook1-certificate", + }, + }}, + }, + }, + want: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{ + "cert-manager.io/inject-ca-from": "example1-ns/webhook1-certificate", + }, + }, + }, + }, + { + name: "set crd labels", + args: args{ + crd: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + xrd: &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1.CompositeResourceDefinitionSpec{Metadata: &v1.CompositeResourceDefinitionSpecMetadata{ + Labels: map[string]string{ + "example.com/some-crd-label": "value1", + "example.com/some-additional-crd-label": "value2", + }, + }}, + }, + }, + want: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{ + "example.com/some-crd-label": "value1", + "example.com/some-additional-crd-label": "value2", + }, + }, + }, + }, + { + name: "append labels", + args: args{ + crd: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + xrd: &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{ + "example.com/some-xrd-label": "value1", + "example.com/some-additional-xrd-label": "value2", + }, + }, + Spec: v1.CompositeResourceDefinitionSpec{Metadata: &v1.CompositeResourceDefinitionSpecMetadata{ + Labels: map[string]string{ + "example.com/some-crd-label": "value3", + "example.com/some-additional-crd-label": "value4", + }, + }}, + }, + }, + want: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{ + "example.com/some-xrd-label": "value1", + "example.com/some-additional-xrd-label": "value2", + "example.com/some-crd-label": "value3", + "example.com/some-additional-crd-label": "value4", + }, + }, + }, + }, + { + name: "labels and annotations", + args: args{ + crd: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + xrd: &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{ + "example.com/some-xrd-annotation": "not-propagated", + "example.com/some-additional-xrd-label-annotation": "not-propagated", + }, + Labels: map[string]string{ + "example.com/some-xrd-label": "value1", + "example.com/some-additional-xrd-label": "value2", + }, + }, + Spec: v1.CompositeResourceDefinitionSpec{Metadata: &v1.CompositeResourceDefinitionSpecMetadata{ + Annotations: map[string]string{ + "example.com/some-crd-annotation": "value1", + "example.com/some-additional-crd-label-annotation": "value2", + }, + Labels: map[string]string{ + "example.com/some-crd-label": "value3", + "example.com/some-additional-crd-label": "value4", + }, + }}, + }, + }, + want: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Annotations: map[string]string{ + "example.com/some-crd-annotation": "value1", + "example.com/some-additional-crd-label-annotation": "value2", + }, + Labels: map[string]string{ + "example.com/some-xrd-label": "value1", + "example.com/some-additional-xrd-label": "value2", + "example.com/some-crd-label": "value3", + "example.com/some-additional-crd-label": "value4", + }, + }, + }, + }, + { + name: "no labels and no annotations", + args: args{ + crd: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + xrd: &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + }, + want: &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := setCrdMetadata(tt.args.crd, tt.args.xrd) + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("setCrdMetadata(...): -want, +got:\n%s", diff) + } + }) + } +} From 731d33a92a33bf4a1fb50aae70a1a7811a7ef35e Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 17:00:39 +0200 Subject: [PATCH 046/148] controller/rbac/namespace: edge based events for role updates Signed-off-by: Dr. Stefan Schimanski --- internal/controller/rbac/namespace/reconciler.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/controller/rbac/namespace/reconciler.go b/internal/controller/rbac/namespace/reconciler.go index c51906638..ba64885f6 100644 --- a/internal/controller/rbac/namespace/reconciler.go +++ b/internal/controller/rbac/namespace/reconciler.go @@ -19,6 +19,8 @@ package namespace import ( "context" + "fmt" + "sort" "strings" "time" @@ -193,8 +195,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{}, err } + var applied []string //nolint:prealloc // We don't know how many roles we'll apply. for _, rl := range r.rbac.RenderRoles(ns, l.Items) { - log = log.WithValues("role-name", rl.GetName()) + log := log.WithValues("role-name", rl.GetName()) rl := rl // Pin range variable so we can take its address. err := r.client.Apply(ctx, &rl, resource.MustBeControllableBy(ns.GetUID()), resource.AllowUpdateIf(RolesDiffer)) @@ -210,9 +213,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco } log.Debug("Applied RBAC Role") + applied = append(applied, rl.GetName()) } - r.record.Event(ns, event.Normal(reasonApplyRoles, "Applied RBAC Roles")) + sort.Strings(applied) + if len(applied) > 3 { + r.record.Event(ns, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC Roles: %s, %s, %s, and %d more", applied[0], applied[1], applied[2], len(applied)-3))) + } else if len(applied) > 0 { + r.record.Event(ns, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC Roles: %s", strings.Join(applied, ", ")))) + } return reconcile.Result{Requeue: false}, nil } From e9ec86098f21966e0e266f5c45dc9be70529283f Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 17:00:39 +0200 Subject: [PATCH 047/148] controller/rbac/provider/binding: edge based events for ClusterRoleBinding apply Signed-off-by: Dr. Stefan Schimanski --- .../rbac/provider/binding/reconciler.go | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/internal/controller/rbac/provider/binding/reconciler.go b/internal/controller/rbac/provider/binding/reconciler.go index 014decf75..64f46fba1 100644 --- a/internal/controller/rbac/provider/binding/reconciler.go +++ b/internal/controller/rbac/provider/binding/reconciler.go @@ -19,12 +19,15 @@ package binding import ( "context" + "fmt" "strings" "time" + "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -171,6 +174,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco // ProviderRevision. Each revision should control at most one, but it's easy // and relatively harmless for us to handle there being many. subjects := make([]rbacv1.Subject, 0) + subjectStrings := make([]string, 0) for _, sa := range l.Items { for _, ref := range sa.GetOwnerReferences() { if ref.UID == pr.GetUID() { @@ -179,6 +183,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco Namespace: sa.GetNamespace(), Name: sa.GetName(), }) + subjectStrings = append(subjectStrings, sa.GetNamespace()+"/"+sa.GetName()) } } } @@ -204,15 +209,25 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco "subjects", subjects, ) - if err := r.client.Apply(ctx, rb, resource.MustBeControllableBy(pr.GetUID())); err != nil { + if err := r.client.Apply(ctx, rb, resource.MustBeControllableBy(pr.GetUID()), resource.AllowUpdateIf(ClusterRoleBindingsDiffer)); err != nil && !resource.IsNotAllowed(err) { log.Debug(errApplyBinding, "error", err) err = errors.Wrap(err, errApplyBinding) r.record.Event(pr, event.Warning(reasonBind, err)) return reconcile.Result{}, err + } else if err == nil { + r.record.Event(pr, event.Normal(reasonBind, fmt.Sprintf("Bound system ClusterRole %q to provider ServiceAccount(s): %s", n, strings.Join(subjectStrings, ", ")))) + log.Debug("Applied system ClusterRoleBinding") } - log.Debug("Applied system ClusterRoleBinding") - r.record.Event(pr, event.Normal(reasonBind, "Bound system ClusterRole to provider ServiceAccount(s)")) // There's no need to requeue explicitly - we're watching all PRs. return reconcile.Result{Requeue: false}, nil } + +// ClusterRoleBindingsDiffer returns true if the supplied objects are different ClusterRoleBindings. We +// consider ClusterRoleBindings to be different if the subjects, the roleRefs, or the owner ref +// is different. +func ClusterRoleBindingsDiffer(current, desired runtime.Object) bool { + c := current.(*rbacv1.ClusterRoleBinding) + d := desired.(*rbacv1.ClusterRoleBinding) + return !cmp.Equal(c.Subjects, d.Subjects) || !cmp.Equal(c.RoleRef, d.RoleRef) || !cmp.Equal(c.GetOwnerReferences(), d.GetOwnerReferences()) +} From 0702d10e8ec7e49438728f054e6462e9ae4fa267 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 17:00:39 +0200 Subject: [PATCH 048/148] controller/rbac/definition: edge based events for ClusterRole apply Signed-off-by: Dr. Stefan Schimanski --- internal/controller/rbac/definition/reconciler.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/internal/controller/rbac/definition/reconciler.go b/internal/controller/rbac/definition/reconciler.go index 86d5faaf6..290a7b71d 100644 --- a/internal/controller/rbac/definition/reconciler.go +++ b/internal/controller/rbac/definition/reconciler.go @@ -19,6 +19,8 @@ package definition import ( "context" + "fmt" + "sort" "strings" "time" @@ -178,9 +180,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{Requeue: false}, nil } + applied := make([]string, 0) for _, cr := range r.rbac.RenderClusterRoles(d) { cr := cr // Pin range variable so we can take its address. - log = log.WithValues("role-name", cr.GetName()) + log := log.WithValues("role-name", cr.GetName()) err := r.client.Apply(ctx, &cr, resource.MustBeControllableBy(d.GetUID()), resource.AllowUpdateIf(ClusterRolesDiffer)) if resource.IsNotAllowed(err) { log.Debug("Skipped no-op RBAC ClusterRole apply") @@ -193,11 +196,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{}, err } log.Debug("Applied RBAC ClusterRole") + applied = append(applied, cr.GetName()) + } + + sort.Strings(applied) + if len(applied) > 3 { + r.record.Event(d, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s, %s, %s, and %d more", applied[0], applied[1], applied[2], len(applied)-3))) + } else if len(applied) > 0 { + r.record.Event(d, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s", strings.Join(applied, ", ")))) } // TODO(negz): Add a condition that indicates the RBAC manager is managing // cluster roles for this XRD? - r.record.Event(d, event.Normal(reasonApplyRoles, "Applied RBAC ClusterRoles")) // There's no need to requeue explicitly - we're watching all XRDs. return reconcile.Result{Requeue: false}, nil From 63a3eea5b8831401ad91d9c8829ac25d235f9cae Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 17:00:39 +0200 Subject: [PATCH 049/148] controller/rbac/provider/roles: edge based events for ClusterRole apply Signed-off-by: Dr. Stefan Schimanski --- .../controller/rbac/provider/roles/reconciler.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/internal/controller/rbac/provider/roles/reconciler.go b/internal/controller/rbac/provider/roles/reconciler.go index 251afd00e..317ccaf80 100644 --- a/internal/controller/rbac/provider/roles/reconciler.go +++ b/internal/controller/rbac/provider/roles/reconciler.go @@ -19,6 +19,8 @@ package roles import ( "context" + "fmt" + "sort" "strings" "time" @@ -322,9 +324,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{Requeue: false}, nil } + applied := make([]string, 0) for _, cr := range r.rbac.RenderClusterRoles(pr, resources) { cr := cr // Pin range variable so we can take its address. - log = log.WithValues("role-name", cr.GetName()) + log := log.WithValues("role-name", cr.GetName()) err := r.client.Apply(ctx, &cr, resource.MustBeControllableBy(pr.GetUID()), resource.AllowUpdateIf(ClusterRolesDiffer)) if resource.IsNotAllowed(err) { log.Debug("Skipped no-op RBAC ClusterRole apply") @@ -337,11 +340,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{}, err } log.Debug("Applied RBAC ClusterRole") + applied = append(applied, cr.GetName()) + } + + sort.Strings(applied) + if len(applied) > 3 { + r.record.Event(pr, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s, %s, %s, and %d more", applied[0], applied[1], applied[2], len(applied)-3))) + } else if len(applied) > 0 { + r.record.Event(pr, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s", strings.Join(applied, ", ")))) } // TODO(negz): Add a condition that indicates the RBAC manager is // managing cluster roles for this ProviderRevision? - r.record.Event(pr, event.Normal(reasonApplyRoles, "Applied RBAC ClusterRoles")) // There's no need to requeue explicitly - we're watching all PRs. return reconcile.Result{Requeue: false}, nil From bb584259e17f14e23fdf36bec9800f61e4969ce6 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 17:00:40 +0200 Subject: [PATCH 050/148] Address comments: firstNAndSomeMore Signed-off-by: Dr. Stefan Schimanski --- .../controller/rbac/definition/reconciler.go | 15 ++++++++++----- internal/controller/rbac/namespace/reconciler.go | 16 +++++++++++----- .../rbac/provider/binding/reconciler.go | 13 +++++++++---- .../controller/rbac/provider/roles/reconciler.go | 15 ++++++++++----- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/internal/controller/rbac/definition/reconciler.go b/internal/controller/rbac/definition/reconciler.go index 290a7b71d..2a861b8f3 100644 --- a/internal/controller/rbac/definition/reconciler.go +++ b/internal/controller/rbac/definition/reconciler.go @@ -199,11 +199,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco applied = append(applied, cr.GetName()) } - sort.Strings(applied) - if len(applied) > 3 { - r.record.Event(d, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s, %s, %s, and %d more", applied[0], applied[1], applied[2], len(applied)-3))) - } else if len(applied) > 0 { - r.record.Event(d, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s", strings.Join(applied, ", ")))) + if len(applied) > 0 { + sort.Strings(applied) + r.record.Event(d, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s", firstNAndSomeMore(applied)))) } // TODO(negz): Add a condition that indicates the RBAC manager is managing @@ -221,3 +219,10 @@ func ClusterRolesDiffer(current, desired runtime.Object) bool { d := desired.(*rbacv1.ClusterRole) return !cmp.Equal(c.GetLabels(), d.GetLabels()) || !cmp.Equal(c.Rules, d.Rules) } + +func firstNAndSomeMore(names []string) string { + if len(names) > 3 { + return fmt.Sprintf("%s, and %d more", strings.Join(names[:3], ", "), len(names)-3) + } + return strings.Join(names, ", ") +} diff --git a/internal/controller/rbac/namespace/reconciler.go b/internal/controller/rbac/namespace/reconciler.go index ba64885f6..7b0dcf1c6 100644 --- a/internal/controller/rbac/namespace/reconciler.go +++ b/internal/controller/rbac/namespace/reconciler.go @@ -216,12 +216,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco applied = append(applied, rl.GetName()) } - sort.Strings(applied) - if len(applied) > 3 { - r.record.Event(ns, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC Roles: %s, %s, %s, and %d more", applied[0], applied[1], applied[2], len(applied)-3))) - } else if len(applied) > 0 { - r.record.Event(ns, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC Roles: %s", strings.Join(applied, ", ")))) + if len(applied) > 0 { + sort.Strings(applied) + r.record.Event(ns, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC Roles: %s", firstNAndSomeMore(applied)))) } + return reconcile.Result{Requeue: false}, nil } @@ -251,3 +250,10 @@ func equalRolesAnnotations(current, desired *rbacv1.Role) bool { } return cmp.Equal(currentFiltered, desiredFiltered) } + +func firstNAndSomeMore(names []string) string { + if len(names) > 3 { + return fmt.Sprintf("%s, and %d more", strings.Join(names[:3], ", "), len(names)-3) + } + return strings.Join(names, ", ") +} diff --git a/internal/controller/rbac/provider/binding/reconciler.go b/internal/controller/rbac/provider/binding/reconciler.go index 64f46fba1..5600f8ab9 100644 --- a/internal/controller/rbac/provider/binding/reconciler.go +++ b/internal/controller/rbac/provider/binding/reconciler.go @@ -209,16 +209,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco "subjects", subjects, ) - if err := r.client.Apply(ctx, rb, resource.MustBeControllableBy(pr.GetUID()), resource.AllowUpdateIf(ClusterRoleBindingsDiffer)); err != nil && !resource.IsNotAllowed(err) { + err := r.client.Apply(ctx, rb, resource.MustBeControllableBy(pr.GetUID()), resource.AllowUpdateIf(ClusterRoleBindingsDiffer)) + if resource.IsNotAllowed(err) { + log.Debug("Skipped no-op ClusterRoleBinding apply") + return reconcile.Result{}, nil + } + if err != nil { log.Debug(errApplyBinding, "error", err) err = errors.Wrap(err, errApplyBinding) r.record.Event(pr, event.Warning(reasonBind, err)) return reconcile.Result{}, err - } else if err == nil { - r.record.Event(pr, event.Normal(reasonBind, fmt.Sprintf("Bound system ClusterRole %q to provider ServiceAccount(s): %s", n, strings.Join(subjectStrings, ", ")))) - log.Debug("Applied system ClusterRoleBinding") } + r.record.Event(pr, event.Normal(reasonBind, fmt.Sprintf("Bound system ClusterRole %q to provider ServiceAccount(s): %s", n, strings.Join(subjectStrings, ", ")))) + log.Debug("Applied system ClusterRoleBinding") + // There's no need to requeue explicitly - we're watching all PRs. return reconcile.Result{Requeue: false}, nil } diff --git a/internal/controller/rbac/provider/roles/reconciler.go b/internal/controller/rbac/provider/roles/reconciler.go index 317ccaf80..1f0027d39 100644 --- a/internal/controller/rbac/provider/roles/reconciler.go +++ b/internal/controller/rbac/provider/roles/reconciler.go @@ -343,11 +343,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco applied = append(applied, cr.GetName()) } - sort.Strings(applied) - if len(applied) > 3 { - r.record.Event(pr, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s, %s, %s, and %d more", applied[0], applied[1], applied[2], len(applied)-3))) - } else if len(applied) > 0 { - r.record.Event(pr, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s", strings.Join(applied, ", ")))) + if len(applied) > 0 { + sort.Strings(applied) + r.record.Event(pr, event.Normal(reasonApplyRoles, fmt.Sprintf("Applied RBAC ClusterRoles: %s", firstNAndSomeMore(applied)))) } // TODO(negz): Add a condition that indicates the RBAC manager is @@ -431,3 +429,10 @@ func (d OrgDiffer) Differs(a, b string) bool { return oa != ob } + +func firstNAndSomeMore(names []string) string { + if len(names) > 3 { + return fmt.Sprintf("%s, and %d more", strings.Join(names[:3], ", "), len(names)-3) + } + return strings.Join(names, ", ") +} From 534633ecbd473cf80db929126d9cd0dfd33274d8 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Tue, 11 Jul 2023 17:47:08 +0200 Subject: [PATCH 051/148] chore: rename error constants according to our standard Signed-off-by: Philippe Scorsolini --- .../controller/pkg/resolver/reconciler.go | 8 ++-- .../controller/pkg/revision/dependency.go | 10 ++--- .../pkg/revision/dependency_test.go | 6 +-- internal/initializer/installer_test.go | 40 +++++++++---------- internal/xpkg/lint.go | 6 +-- internal/xpkg/lint_test.go | 4 +- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/internal/controller/pkg/resolver/reconciler.go b/internal/controller/pkg/resolver/reconciler.go index 44f37fce5..a53fd58d4 100644 --- a/internal/controller/pkg/resolver/reconciler.go +++ b/internal/controller/pkg/resolver/reconciler.go @@ -58,12 +58,12 @@ const ( errRemoveFinalizer = "cannot remove lock finalizer" errBuildDAG = "cannot build DAG" errSortDAG = "cannot sort DAG" - errMissingDependencyFmt = "missing package (%s) is not a dependency" + errFmtMissingDependency = "missing package (%s) is not a dependency" errInvalidConstraint = "version constraint on dependency is invalid" errInvalidDependency = "dependency package is not valid" errFetchTags = "cannot fetch dependency package tags" errNoValidVersion = "cannot find a valid version for package constraints" - errNoValidVersionFmt = "dependency (%s) does not have version in constraints (%s)" + errFmtNoValidVersion = "dependency (%s) does not have version in constraints (%s)" errInvalidPackageType = "cannot create invalid package dependency type" errCreateDependency = "cannot create dependency package" ) @@ -216,7 +216,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco // check for missing nodes again. dep, ok := implied[0].(*v1beta1.Dependency) if !ok { - log.Debug(errInvalidDependency, "error", errors.Errorf(errMissingDependencyFmt, dep.Identifier())) + log.Debug(errInvalidDependency, "error", errors.Errorf(errFmtMissingDependency, dep.Identifier())) return reconcile.Result{Requeue: false}, nil } c, err := semver.NewConstraint(dep.Constraints) @@ -260,7 +260,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco // NOTE(hasheddan): consider creating event on package revision // dictating constraints. if addVer == "" { - log.Debug(errNoValidVersion, "error", errors.Errorf(errNoValidVersionFmt, dep.Identifier(), dep.Constraints)) + log.Debug(errNoValidVersion, "error", errors.Errorf(errFmtNoValidVersion, dep.Identifier(), dep.Constraints)) return reconcile.Result{Requeue: false}, nil } diff --git a/internal/controller/pkg/revision/dependency.go b/internal/controller/pkg/revision/dependency.go index 38bf32470..0a2ed47fc 100644 --- a/internal/controller/pkg/revision/dependency.go +++ b/internal/controller/pkg/revision/dependency.go @@ -41,8 +41,8 @@ const ( errNotMeta = "meta type is not a valid package" errGetOrCreateLock = "cannot get or create lock" errInitDAG = "cannot initialize dependency graph from the packages in the lock" - errIncompatibleDependencyFmt = "incompatible dependencies: %+v" - errMissingDependenciesFmt = "missing dependencies: %+v" + errFmtIncompatibleDependency = "incompatible dependencies: %+v" + errFmtMissingDependencies = "missing dependencies: %+v" errDependencyNotInGraph = "dependency is not present in graph" errDependencyNotLockPackage = "dependency in graph is not a lock package" ) @@ -160,7 +160,7 @@ func (m *PackageDependencyManager) Resolve(ctx context.Context, pkg runtime.Obje missing = append(missing, dep.Identifier()) } if installed != found { - return found, installed, invalid, errors.Errorf(errMissingDependenciesFmt, missing) + return found, installed, invalid, errors.Errorf(errFmtMissingDependencies, missing) } } @@ -179,7 +179,7 @@ func (m *PackageDependencyManager) Resolve(ctx context.Context, pkg runtime.Obje } } if len(missing) != 0 { - return found, installed, invalid, errors.Errorf(errMissingDependenciesFmt, missing) + return found, installed, invalid, errors.Errorf(errFmtMissingDependencies, missing) } // All of our dependencies and transitive dependencies must exist. Check @@ -208,7 +208,7 @@ func (m *PackageDependencyManager) Resolve(ctx context.Context, pkg runtime.Obje } invalid = len(invalidDeps) if invalid > 0 { - return found, installed, invalid, errors.Errorf(errIncompatibleDependencyFmt, invalidDeps) + return found, installed, invalid, errors.Errorf(errFmtIncompatibleDependency, invalidDeps) } return found, installed, invalid, nil } diff --git a/internal/controller/pkg/revision/dependency_test.go b/internal/controller/pkg/revision/dependency_test.go index 4543db983..8ad5d3d05 100644 --- a/internal/controller/pkg/revision/dependency_test.go +++ b/internal/controller/pkg/revision/dependency_test.go @@ -353,7 +353,7 @@ func TestResolve(t *testing.T) { }, want: want{ total: 2, - err: errors.Errorf(errMissingDependenciesFmt, []string{"not-here-1", "not-here-2"}), + err: errors.Errorf(errFmtMissingDependencies, []string{"not-here-1", "not-here-2"}), }, }, "ErrorSelfExistMissingDependencies": { @@ -441,7 +441,7 @@ func TestResolve(t *testing.T) { want: want{ total: 3, installed: 1, - err: errors.Errorf(errMissingDependenciesFmt, []string{"not-here-2", "not-here-3"}), + err: errors.Errorf(errFmtMissingDependencies, []string{"not-here-2", "not-here-3"}), }, }, "ErrorSelfExistInvalidDependencies": { @@ -540,7 +540,7 @@ func TestResolve(t *testing.T) { total: 3, installed: 3, invalid: 2, - err: errors.Errorf(errIncompatibleDependencyFmt, []string{"not-here-1", "not-here-2"}), + err: errors.Errorf(errFmtIncompatibleDependency, []string{"not-here-1", "not-here-2"}), }, }, "SuccessfulSelfExistValidDependencies": { diff --git a/internal/initializer/installer_test.go b/internal/initializer/installer_test.go index cc6f64373..6a4ffd62b 100644 --- a/internal/initializer/installer_test.go +++ b/internal/initializer/installer_test.go @@ -34,12 +34,12 @@ import ( ) const ( - errGetProviderFmt = "unexpected name in provider get: %s" - errPatchProviderFmt = "unexpected name in provider update: %s" - errPatchProviderSourceFmt = "unexpected source in provider update: %s" - errGetConfigurationFmt = "unexpected name in configuration get: %s" - errPatchConfigurationFmt = "unexpected name in configuration update: %s" - errPatchConfigurationSourceFmt = "unexpected source in configuration update: %s" + errFmtGetProvider = "unexpected name in provider get: %s" + errFmtPatchProvider = "unexpected name in provider update: %s" + errFmtPatchProviderSource = "unexpected source in provider update: %s" + errFmtGetConfiguration = "unexpected name in configuration get: %s" + errFmtPatchConfiguration = "unexpected name in configuration update: %s" + errFmtPatchConfigurationSource = "unexpected source in configuration update: %s" ) var errBoom = errors.New("boom") @@ -111,11 +111,11 @@ func TestInstaller(t *testing.T) { switch obj.(type) { case *v1.Provider: if key.Name != p1Name { - t.Errorf(errGetProviderFmt, key.Name) + t.Errorf(errFmtGetProvider, key.Name) } case *v1.Configuration: if key.Name != c1Name { - t.Errorf(errGetConfigurationFmt, key.Name) + t.Errorf(errFmtGetConfiguration, key.Name) } default: t.Errorf("unexpected type") @@ -126,11 +126,11 @@ func TestInstaller(t *testing.T) { switch obj.(type) { case *v1.Provider: if obj.GetName() != p1Name { - t.Errorf(errPatchProviderFmt, obj.GetName()) + t.Errorf(errFmtPatchProvider, obj.GetName()) } case *v1.Configuration: if obj.GetName() != c1Name { - t.Errorf(errPatchConfigurationFmt, obj.GetName()) + t.Errorf(errFmtPatchConfiguration, obj.GetName()) } default: t.Errorf("unexpected type") @@ -186,11 +186,11 @@ func TestInstaller(t *testing.T) { switch obj.(type) { case *v1.Provider: if key.Name != p1Existing { - t.Errorf(errGetProviderFmt, key.Name) + t.Errorf(errFmtGetProvider, key.Name) } case *v1.Configuration: if key.Name != c1Existing { - t.Errorf(errGetConfigurationFmt, key.Name) + t.Errorf(errFmtGetConfiguration, key.Name) } default: t.Errorf("unexpected type") @@ -201,17 +201,17 @@ func TestInstaller(t *testing.T) { switch o := obj.(type) { case *v1.Provider: if o.GetName() != p1Existing { - t.Errorf(errPatchProviderFmt, o.GetName()) + t.Errorf(errFmtPatchProvider, o.GetName()) } if o.GetSource() != p1 { - t.Errorf(errPatchProviderSourceFmt, o.GetSource()) + t.Errorf(errFmtPatchProviderSource, o.GetSource()) } case *v1.Configuration: if o.GetName() != c1Existing { - t.Errorf(errPatchConfigurationFmt, o.GetName()) + t.Errorf(errFmtPatchConfiguration, o.GetName()) } if o.GetSource() != c1 { - t.Errorf(errPatchConfigurationSourceFmt, o.GetSource()) + t.Errorf(errFmtPatchConfigurationSource, o.GetSource()) } default: t.Errorf("unexpected type") @@ -233,11 +233,11 @@ func TestInstaller(t *testing.T) { switch obj.(type) { case *v1.Provider: if key.Name != p1Name { - t.Errorf(errGetProviderFmt, key.Name) + t.Errorf(errFmtGetProvider, key.Name) } case *v1.Configuration: if key.Name != c1Name { - t.Errorf(errGetConfigurationFmt, key.Name) + t.Errorf(errFmtGetConfiguration, key.Name) } default: t.Errorf("unexpected type") @@ -293,11 +293,11 @@ func TestInstaller(t *testing.T) { switch obj.(type) { case *v1.Provider: if key.Name != p1Name { - t.Errorf(errGetProviderFmt, key.Name) + t.Errorf(errFmtGetProvider, key.Name) } case *v1.Configuration: if key.Name != c1Name { - t.Errorf(errGetConfigurationFmt, key.Name) + t.Errorf(errFmtGetConfiguration, key.Name) } default: t.Errorf("unexpected type") diff --git a/internal/xpkg/lint.go b/internal/xpkg/lint.go index 1e4ccbbd6..80f30c43b 100644 --- a/internal/xpkg/lint.go +++ b/internal/xpkg/lint.go @@ -44,7 +44,7 @@ const ( errNotValidatingWebhookConfiguration = "object is not an ValidatingWebhookConfiguration" errNotComposition = "object is not a Composition" errBadConstraints = "package version constraints are poorly formatted" - errCrossplaneIncompatibleFmt = "package is not compatible with Crossplane version (%s)" + errFmtCrossplaneIncompatible = "package is not compatible with Crossplane version (%s)" ) // NewProviderLinter is a convenience function for creating a package linter for @@ -118,10 +118,10 @@ func PackageCrossplaneCompatible(v version.Operations) parser.ObjectLinterFn { } in, err := v.InConstraints(p.GetCrossplaneConstraints().Version) if err != nil { - return errors.Wrapf(err, errCrossplaneIncompatibleFmt, v.GetVersionString()) + return errors.Wrapf(err, errFmtCrossplaneIncompatible, v.GetVersionString()) } if !in { - return errors.Errorf(errCrossplaneIncompatibleFmt, v.GetVersionString()) + return errors.Errorf(errFmtCrossplaneIncompatible, v.GetVersionString()) } return nil } diff --git a/internal/xpkg/lint_test.go b/internal/xpkg/lint_test.go index cdbce8cd4..a25741b1f 100644 --- a/internal/xpkg/lint_test.go +++ b/internal/xpkg/lint_test.go @@ -294,7 +294,7 @@ func TestPackageCrossplaneCompatible(t *testing.T) { MockGetVersionString: fake.NewMockGetVersionStringFn("v0.12.0"), }, }, - err: errors.Wrapf(errBoom, errCrossplaneIncompatibleFmt, "v0.12.0"), + err: errors.Wrapf(errBoom, errFmtCrossplaneIncompatible, "v0.12.0"), }, "ErrOutsideConstraints": { reason: "Should return error if Crossplane version outside constraints.", @@ -313,7 +313,7 @@ func TestPackageCrossplaneCompatible(t *testing.T) { MockGetVersionString: fake.NewMockGetVersionStringFn("v0.12.0"), }, }, - err: errors.Errorf(errCrossplaneIncompatibleFmt, "v0.12.0"), + err: errors.Errorf(errFmtCrossplaneIncompatible, "v0.12.0"), }, "ErrNotMeta": { reason: "Should return error if object is not a meta package type.", From cdb04ae6f3b3263f36532c3c5171931fac244c5b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:32:15 +0000 Subject: [PATCH 052/148] Update dependency golang to v1.20.6 --- .github/workflows/ci.yml | 2 +- .github/workflows/promote.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8465ba26a..6a20f0a98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: env: # Common versions - GO_VERSION: '1.20.5' + GO_VERSION: '1.20.6' GOLANGCI_VERSION: 'v1.53.3' DOCKER_BUILDX_VERSION: 'v0.10.0' diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 2c1228282..b52d7c039 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -13,7 +13,7 @@ on: env: # Common versions - GO_VERSION: '1.20.5' + GO_VERSION: '1.20.6' # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether From 5d59c3e7e858c4ced3e503a2049b3205ddc3d5e9 Mon Sep 17 00:00:00 2001 From: dee0sap <82829708+dee0sap@users.noreply.github.com> Date: Tue, 11 Jul 2023 20:31:08 -0700 Subject: [PATCH 053/148] Update ADOPTERS.md with SAP entry Signed-off-by: dee0sap <82829708+dee0sap@users.noreply.github.com> --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index 89a475e29..b7de3eb1a 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -51,3 +51,4 @@ This list is sorted in the order that organizations were added to it. | [PITS Global Data Recovery Services](https://www.pitsdatarecovery.net/) | @pheianox | Declarative configuration and integration with CI/CD pipelines | | [NASA Science Cloud](https://smce.nasa.gov/) | [ramon.e.ramirez-linan@nasa.gov](mailto:ramon.e.ramirez-linan@nasa.gov) ([@rezuma](https://github.com/rezuma)) | [NASA Science Cloud](https://smce.nasa.gov) has created compositions to deploy the Open Science Studio, a jupyterhub based platform that connects to HPC in the cloud and foster NASA Open Science Initiative. Navteca ([@navteca](https://github.com/Navteca)) has been helping NASA with this initiative | | [Navteca](https://navteca.com/) | [rlinan@navteca.com](mailto:rlinan@navteca.com) ([@navteca](https://github.com/Navteca)) | [Navteca](https://www.navteca.com) is adopting Crossplane to deploy [Voice Atlas](https://www.voiceatlas.com) a cloud based product that let customer connect corporate knowledge with any Large Language Model and offered to be consumed by users through any channel (slack, MS Teams, Website, etc) | +| [SAP](https://sap.com/) | [d.small@sap.com](mailto:d.small@sap.com)| [SAP](https://sap.com) uses Crossplane as part of a solution that gives teams owning micro-services the ability to provision hyper-scaler hosted backing services such as Redis on demand. | From d6195229a8bcefab77c0f26e2de86401950f3313 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 22:26:57 -0700 Subject: [PATCH 054/148] Make @phisco a Crossplane maintainer Philippe has lead an implemented an impactful design for us in the form of Composition Validation. He's also proven to be pragmatic and easy to collaborate with, and willing to drive laborious but high-value processes like introducing Renovate and liasing with the security audit team. Signed-off-by: Nic Cope --- OWNERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OWNERS.md b/OWNERS.md index 9fbd336f3..872c7e286 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -30,6 +30,7 @@ See [CODEOWNERS](CODEOWNERS) for automatic PR assignment. * Muvaffak Onus ([muvaf](https://github.com/muvaf)) * Hasan Turken ([turkenh](https://github.com/turkenh)) * Bob Haddleton ([bobh66](https://github.com/bobh66)) +* Philippe Scorsolini ([phisco](https://github.com/phisco)) ## Reviewers @@ -37,7 +38,6 @@ See [CODEOWNERS](CODEOWNERS) for automatic PR assignment. * Daren Iott ([nullable-eth](https://github.com/nullable-eth)) * Ezgi Demirel ([ezgidemirel](https://github.com/ezgidemirel)) * Max Blatt ([MisterMX](https://github.com/MisterMX)) -* Philippe Scorsolini ([phisco](https://github.com/phisco)) * Jared Watts ([jbw976](https://github.com/jbw976)) * Lovro Sviben ([lsviben](https://github.com/lsviben)) From 4a131aca9b7af059362431d4bdf7c9388f26f161 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 21:19:10 +0200 Subject: [PATCH 055/148] guide-observability.md: add error guidelines Signed-off-by: Dr. Stefan Schimanski --- contributing/guide-observability.md | 82 ++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/contributing/guide-observability.md b/contributing/guide-observability.md index 9343d0bc7..f3453ec15 100644 --- a/contributing/guide-observability.md +++ b/contributing/guide-observability.md @@ -120,6 +120,86 @@ logs don't show up in production normally. For the question of what constitutes an error, errors should be actionable by a human. See the [Dave Cheney article] on this topic for some more discussion. +## Good Errors + +An error message is good if it communicates + +1. what went wrong +2. where it went wrong +3. for which inputs + +and if it is concise without redundancies and at best displayable in one line. + +The general goal of an error message is to be actionable for the user who is +trying to avoid the error in the future. + +Examples for bad error messages: +- `cannot resolve package dependencies: Invalid Semantic Version` +- `cannot parse file foo.yaml: failed to parse YAML of file foo.yaml` + +Examples for how to improve them: +- `cannot resolve package dependencies in crossplane.yaml: invalid Semantic Version "main" on package "provider-kubernetes"` +- `failed to load OCI image provider-gcp/v0.42.0: failed to unpack layer: cannot parse file: failed to parse YAML of file foo.yaml: unexpected indention in line 4`. + +General rules: +1. follow the pattern `generic error cause: more details: even more details`. +2. put values into quotes (`%q` in Golang), with the following exceptions + where quotes don't add to readability: + - resource names with namespace or resource type (e.g. `default/foo` or + `providers/foo`), resource names alone are quoted + - kinds (e.g. `cannot find provider "provider-kubernetes"`; here, the kind + provider is without quotes, the provider name is with) + - filenames with extensions and/or path (e.g. `cannot parse foo.yaml`). +3. add a context of e.g. filenames, object names, or values which are wrong + (and the values are known to be insensitive). + + Which context is added by which functions depends on the level of + abstraction of the code at hand: the package loader will know the OCI + image name, the YAML parser might only see a byte slice. The former adds + the image name as context, some layer in-between adds the filename and + the YAML parser adds the line and column in the byte stream. + + Filenames should be relative to the logical working directory of the + context at hand (e.g. a package root, current working directory, + workspace root). Ensure that the context is clear in the error message (e.g. + `failed to load package "provider-kubernetes": failed to parse apis/xrd.yaml`). + +4. add a context just once. + + Rule of thumb: if a function gets a parameter, it will also include it in the + error messages, so the caller does not have to. + + E.g. a function getting a filename as input will include the filename in + errors it returns. +5. don't return multi-line errors. +6. aggregate errors if there is clear use for the user, but not in general, i.e. + fail fast is the default. + + Aggregate through `kerrors.NewAggregate`. When the number of aggregated + errors is unbounded, return a subset, e.g. the first 3. + + E.g.: `cannot parse workspace: failed to parse foo.yaml, bar.yaml, abc.yaml, + and 17 more files` +7. don't include sensitive information like tokens into error messages, not even + in debug mode. + + These are usually considered insensitive: field names, file paths, resources, + kinds, object names, namespaces, labels, enum values, numbers, booleans. +8. use error message constants, e.g. `errSomethingWentWrong` for messages + without interpolation, and `errFmtSomethingWentWrong` for those with + interpolation. +9. use [wrapping errors] and github.com/crossplane/crossplane-runtime/pkg/errors + in general. +10. error messages must be deterministic. Use sorting in loops over maps or sort + returned errors to ensure determinism. + + Background: one never knows how an error is displayed. Not being + deterministic can lead to hot-loops with constant API updates, e.g. of a + condition. + +11. error messages are good candidates to be included in condition or event + messages. + ## In Practice Crossplane provides two observability libraries as part of crossplane-runtime: @@ -187,5 +267,5 @@ implementations. [not]: https://dave.cheney.net/2017/01/23/the-package-level-logger-anti-pattern [`Reconciler`]: https://godoc.org/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler [managed resource reconciler]: https://github.com/crossplane/crossplane-runtime/blob/a6bb0/pkg/reconciler/managed/reconciler.go#L436 -[wrapping errors]: https://godoc.org/github.com/pkg/errors#Wrap +[wrapping errors]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/errors#Wrap [API conventions]: https://github.com/kubernetes/community/blob/09f55c6/contributors/devel/sig-architecture/api-conventions.md#events From 055a46e3f536b45ff4107d1d3da2e01ae58d8196 Mon Sep 17 00:00:00 2001 From: Matej Ohradzansky Date: Sun, 18 Jun 2023 16:03:13 +0200 Subject: [PATCH 056/148] feat: improve environment config * add resolve & resolution policies - support update of config references in XR * sort selected configs to ensure deterministig order while merging * enable user to specify fieldPath to values that sorting alg. compares & support float, int, string comparisons * add maxMatch to limit the number of selected configs refs passed to XR Signed-off-by: Matej Ohradzansky --- .../v1/composition_environment.go | 58 +- .../v1/composition_environment_test.go | 86 +++ .../v1/zz_generated.conversion.go | 29 + .../apiextensions/v1/zz_generated.deepcopy.go | 10 + .../zz_generated.composition_environment.go | 58 +- .../v1beta1/zz_generated.deepcopy.go | 10 + ...ns.crossplane.io_compositionrevisions.yaml | 99 ++- ...extensions.crossplane.io_compositions.yaml | 53 +- .../composite/environment/fetcher.go | 17 +- .../composite/environment/fetcher_test.go | 23 +- .../composite/environment/selector.go | 159 ++++- .../composite/environment/selector_test.go | 613 +++++++++++++++++- .../apiextensions/composite/reconciler.go | 10 +- .../composite/reconciler_test.go | 2 +- 14 files changed, 1165 insertions(+), 62 deletions(-) diff --git a/apis/apiextensions/v1/composition_environment.go b/apis/apiextensions/v1/composition_environment.go index 98f73f77a..941bd74f5 100644 --- a/apis/apiextensions/v1/composition_environment.go +++ b/apis/apiextensions/v1/composition_environment.go @@ -17,8 +17,11 @@ limitations under the License. package v1 import ( + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation/field" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane/internal/validation/errors" ) @@ -42,6 +45,11 @@ type EnvironmentConfiguration struct { // Patches is a list of environment patches that are executed before a // composition's resources are composed. Patches []EnvironmentPatch `json:"patches,omitempty"` + + // Policy represents the Resolve and Resolution policies which apply to + // all EnvironmentSourceReferences in EnvironmentConfigs list. + // +optional + Policy *xpv1.Policy `json:"policy,omitempty"` } // Validate the EnvironmentConfiguration. @@ -63,6 +71,28 @@ func (e *EnvironmentConfiguration) Validate() field.ErrorList { return errs } +// IsNoop specifies whether EnvironmentConfiguration should be resolved or not. +func (e *EnvironmentConfiguration) IsNoop(currentRefs []corev1.ObjectReference) bool { + + if e == nil || len(e.EnvironmentConfigs) == 0 { + return true + } + + if len(currentRefs) == 0 { + return false + } + // currentRefs is non-empty list -> trigger update only if policy.resolve is Always + return !e.Policy.IsResolvePolicyAlways() +} + +// IsRequired specifies whether EnvironmentConfiguration is required or not. +func (e *EnvironmentConfiguration) IsRequired() bool { + if e == nil { + return false + } + return !e.Policy.IsResolutionPolicyOptional() +} + // EnvironmentSourceType specifies the way the EnvironmentConfig is selected. type EnvironmentSourceType string @@ -87,7 +117,7 @@ type EnvironmentSource struct { // +optional Ref *EnvironmentSourceReference `json:"ref,omitempty"` - // Selector selects one EnvironmentConfig via labels. + // Selector selects EnvironmentConfig(s) via labels. // +optional Selector *EnvironmentSourceSelector `json:"selector,omitempty"` } @@ -110,6 +140,7 @@ func (e *EnvironmentSource) Validate() *field.Error { if len(e.Selector.MatchLabels) == 0 { return field.Required(field.NewPath("selector", "matchLabels"), "selector must have at least one match label") } + for i, m := range e.Selector.MatchLabels { if err := m.Validate(); err != nil { return errors.WrapFieldError(err, field.NewPath("selector", "matchLabels").Index(i)) @@ -135,8 +166,33 @@ func (e *EnvironmentSourceReference) Validate() *field.Error { return nil } +// EnvironmentSourceSelectorModeType specifies amount of retrieved EnvironmentConfigs +// with matching label. +type EnvironmentSourceSelectorModeType string + +const ( + // EnvironmentSourceSelectorSingleMode extracts only first EnvironmentConfig from the sorted list. + EnvironmentSourceSelectorSingleMode EnvironmentSourceSelectorModeType = "Single" + + // EnvironmentSourceSelectorMultiMode extracts multiple EnvironmentConfigs from the sorted list. + EnvironmentSourceSelectorMultiMode EnvironmentSourceSelectorModeType = "Multiple" +) + // An EnvironmentSourceSelector selects an EnvironmentConfig via labels. type EnvironmentSourceSelector struct { + + // Mode specifies retrieval strategy: "single" or "multiple". + // +kubebuilder:validation:Enum=Single;Multiple + // +kubebuilder:default=Single + Mode EnvironmentSourceSelectorModeType `json:"mode"` + + // MaxMatch specifies the number of extracted EnvironmentConfigs in multi mode, extracts all if nil. + MaxMatch *uint64 `json:"maxMatch,omitempty"` + + // SortByFieldPath is the path to the field based on which list of EnvironmentConfigs is alphabetically sorted. + // +kubebuilder:default="metadata.name" + SortByFieldPath string `json:"sortByFieldPath"` + // MatchLabels ensures an object with matching labels is selected. MatchLabels []EnvironmentSourceSelectorLabelMatcher `json:"matchLabels,omitempty"` } diff --git a/apis/apiextensions/v1/composition_environment_test.go b/apis/apiextensions/v1/composition_environment_test.go index 240c0fcc2..bf9c08c82 100644 --- a/apis/apiextensions/v1/composition_environment_test.go +++ b/apis/apiextensions/v1/composition_environment_test.go @@ -5,8 +5,11 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/utils/pointer" + + v1 "github.com/crossplane/crossplane-runtime/apis/common/v1" ) func TestEnvironmentPatchValidate(t *testing.T) { @@ -75,3 +78,86 @@ func TestEnvironmentPatchValidate(t *testing.T) { }) } } + +func TestEnvironmentIsNoop(t *testing.T) { + + withResolvePolicy := func() *v1.ResolvePolicy { + p := v1.ResolvePolicyAlways + return &p + } + + type args struct { + refs []corev1.ObjectReference + ec *EnvironmentConfiguration + } + + cases := map[string]struct { + reason string + args args + want bool + }{ + "DontResolveWhenHaveRefs": { + reason: "Should not resolve when composite has refs", + args: args{ + ec: &EnvironmentConfiguration{ + EnvironmentConfigs: []EnvironmentSource{{}}, + }, + refs: []corev1.ObjectReference{{}}, + }, + want: true, + }, + "ResolveWhenNoRefs": { + reason: "Should resolve when no refs are held", + args: args{ + ec: &EnvironmentConfiguration{ + EnvironmentConfigs: []EnvironmentSource{{}}, + }, + refs: []corev1.ObjectReference{}, + }, + want: false, + }, + "ResolveWhenPolicyAlways": { + reason: "Should resolve when resolve policy is Always", + args: args{ + ec: &EnvironmentConfiguration{ + EnvironmentConfigs: []EnvironmentSource{ + {}, + }, + Policy: &v1.Policy{ + Resolve: withResolvePolicy(), + }, + }, + refs: []corev1.ObjectReference{ + {}, + {}, + }, + }, + want: false, + }, + "DontResolveWhenPolicyNotAlways": { + reason: "Should not resolve when resolve policy is not Always", + args: args{ + ec: &EnvironmentConfiguration{ + EnvironmentConfigs: []EnvironmentSource{ + {}, + }, + }, + refs: []corev1.ObjectReference{ + {}, + {}, + }, + }, + want: true, + }, + } + + for name, tc := range cases { + + t.Run(name, func(t *testing.T) { + got := tc.args.ec.IsNoop(tc.args.refs) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("%s\nIsNoop(...): -want, +got:\n%s", tc.reason, diff) + } + }) + } +} diff --git a/apis/apiextensions/v1/zz_generated.conversion.go b/apis/apiextensions/v1/zz_generated.conversion.go index 000c5cb20..d529bdf63 100755 --- a/apis/apiextensions/v1/zz_generated.conversion.go +++ b/apis/apiextensions/v1/zz_generated.conversion.go @@ -231,6 +231,7 @@ func (c *GeneratedRevisionSpecConverter) pV1EnvironmentConfigurationToPV1Environ } } v1EnvironmentConfiguration.Patches = v1EnvironmentPatchList + v1EnvironmentConfiguration.Policy = c.pV1PolicyToPV1Policy((*source).Policy) pV1EnvironmentConfiguration = &v1EnvironmentConfiguration } return pV1EnvironmentConfiguration @@ -248,6 +249,14 @@ func (c *GeneratedRevisionSpecConverter) pV1EnvironmentSourceSelectorToPV1Enviro var pV1EnvironmentSourceSelector *EnvironmentSourceSelector if source != nil { var v1EnvironmentSourceSelector EnvironmentSourceSelector + v1EnvironmentSourceSelector.Mode = EnvironmentSourceSelectorModeType((*source).Mode) + var pUint64 *uint64 + if (*source).MaxMatch != nil { + xuint64 := *(*source).MaxMatch + pUint64 = &xuint64 + } + v1EnvironmentSourceSelector.MaxMatch = pUint64 + v1EnvironmentSourceSelector.SortByFieldPath = (*source).SortByFieldPath var v1EnvironmentSourceSelectorLabelMatcherList []EnvironmentSourceSelectorLabelMatcher if (*source).MatchLabels != nil { v1EnvironmentSourceSelectorLabelMatcherList = make([]EnvironmentSourceSelectorLabelMatcher, len((*source).MatchLabels)) @@ -363,6 +372,26 @@ func (c *GeneratedRevisionSpecConverter) pV1PatchPolicyToPV1PatchPolicy(source * } return pV1PatchPolicy } +func (c *GeneratedRevisionSpecConverter) pV1PolicyToPV1Policy(source *v13.Policy) *v13.Policy { + var pV1Policy *v13.Policy + if source != nil { + var v1Policy v13.Policy + var pV1ResolvePolicy *v13.ResolvePolicy + if (*source).Resolve != nil { + v1ResolvePolicy := v13.ResolvePolicy(*(*source).Resolve) + pV1ResolvePolicy = &v1ResolvePolicy + } + v1Policy.Resolve = pV1ResolvePolicy + var pV1ResolutionPolicy *v13.ResolutionPolicy + if (*source).Resolution != nil { + v1ResolutionPolicy := v13.ResolutionPolicy(*(*source).Resolution) + pV1ResolutionPolicy = &v1ResolutionPolicy + } + v1Policy.Resolution = pV1ResolutionPolicy + pV1Policy = &v1Policy + } + return pV1Policy +} func (c *GeneratedRevisionSpecConverter) pV1StoreConfigReferenceToPV1StoreConfigReference(source *StoreConfigReference) *StoreConfigReference { var pV1StoreConfigReference *StoreConfigReference if source != nil { diff --git a/apis/apiextensions/v1/zz_generated.deepcopy.go b/apis/apiextensions/v1/zz_generated.deepcopy.go index 80567a4b5..3237fe53a 100644 --- a/apis/apiextensions/v1/zz_generated.deepcopy.go +++ b/apis/apiextensions/v1/zz_generated.deepcopy.go @@ -806,6 +806,11 @@ func (in *EnvironmentConfiguration) DeepCopyInto(out *EnvironmentConfiguration) (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Policy != nil { + in, out := &in.Policy, &out.Policy + *out = new(commonv1.Policy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvironmentConfiguration. @@ -903,6 +908,11 @@ func (in *EnvironmentSourceReference) DeepCopy() *EnvironmentSourceReference { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EnvironmentSourceSelector) DeepCopyInto(out *EnvironmentSourceSelector) { *out = *in + if in.MaxMatch != nil { + in, out := &in.MaxMatch, &out.MaxMatch + *out = new(uint64) + **out = **in + } if in.MatchLabels != nil { in, out := &in.MatchLabels, &out.MatchLabels *out = make([]EnvironmentSourceSelectorLabelMatcher, len(*in)) diff --git a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go index 3fe523a83..4ea3f76ab 100644 --- a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go +++ b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go @@ -19,8 +19,11 @@ limitations under the License. package v1beta1 import ( + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation/field" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane/internal/validation/errors" ) @@ -44,6 +47,11 @@ type EnvironmentConfiguration struct { // Patches is a list of environment patches that are executed before a // composition's resources are composed. Patches []EnvironmentPatch `json:"patches,omitempty"` + + // Policy represents the Resolve and Resolution policies which apply to + // all EnvironmentSourceReferences in EnvironmentConfigs list. + // +optional + Policy *xpv1.Policy `json:"policy,omitempty"` } // Validate the EnvironmentConfiguration. @@ -65,6 +73,28 @@ func (e *EnvironmentConfiguration) Validate() field.ErrorList { return errs } +// IsNoop specifies whether EnvironmentConfiguration should be resolved or not. +func (e *EnvironmentConfiguration) IsNoop(currentRefs []corev1.ObjectReference) bool { + + if e == nil || len(e.EnvironmentConfigs) == 0 { + return true + } + + if len(currentRefs) == 0 { + return false + } + // currentRefs is non-empty list -> trigger update only if policy.resolve is Always + return !e.Policy.IsResolvePolicyAlways() +} + +// IsRequired specifies whether EnvironmentConfiguration is required or not. +func (e *EnvironmentConfiguration) IsRequired() bool { + if e == nil { + return false + } + return !e.Policy.IsResolutionPolicyOptional() +} + // EnvironmentSourceType specifies the way the EnvironmentConfig is selected. type EnvironmentSourceType string @@ -89,7 +119,7 @@ type EnvironmentSource struct { // +optional Ref *EnvironmentSourceReference `json:"ref,omitempty"` - // Selector selects one EnvironmentConfig via labels. + // Selector selects EnvironmentConfig(s) via labels. // +optional Selector *EnvironmentSourceSelector `json:"selector,omitempty"` } @@ -112,6 +142,7 @@ func (e *EnvironmentSource) Validate() *field.Error { if len(e.Selector.MatchLabels) == 0 { return field.Required(field.NewPath("selector", "matchLabels"), "selector must have at least one match label") } + for i, m := range e.Selector.MatchLabels { if err := m.Validate(); err != nil { return errors.WrapFieldError(err, field.NewPath("selector", "matchLabels").Index(i)) @@ -137,8 +168,33 @@ func (e *EnvironmentSourceReference) Validate() *field.Error { return nil } +// EnvironmentSourceSelectorModeType specifies amount of retrieved EnvironmentConfigs +// with matching label. +type EnvironmentSourceSelectorModeType string + +const ( + // EnvironmentSourceSelectorSingleMode extracts only first EnvironmentConfig from the sorted list. + EnvironmentSourceSelectorSingleMode EnvironmentSourceSelectorModeType = "Single" + + // EnvironmentSourceSelectorMultiMode extracts multiple EnvironmentConfigs from the sorted list. + EnvironmentSourceSelectorMultiMode EnvironmentSourceSelectorModeType = "Multiple" +) + // An EnvironmentSourceSelector selects an EnvironmentConfig via labels. type EnvironmentSourceSelector struct { + + // Mode specifies retrieval strategy: "single" or "multiple". + // +kubebuilder:validation:Enum=Single;Multiple + // +kubebuilder:default=Single + Mode EnvironmentSourceSelectorModeType `json:"mode"` + + // MaxMatch specifies the number of extracted EnvironmentConfigs in multi mode, extracts all if nil. + MaxMatch *uint64 `json:"maxMatch,omitempty"` + + // SortByFieldPath is the path to the field based on which list of EnvironmentConfigs is alphabetically sorted. + // +kubebuilder:default="metadata.name" + SortByFieldPath string `json:"sortByFieldPath"` + // MatchLabels ensures an object with matching labels is selected. MatchLabels []EnvironmentSourceSelectorLabelMatcher `json:"matchLabels,omitempty"` } diff --git a/apis/apiextensions/v1beta1/zz_generated.deepcopy.go b/apis/apiextensions/v1beta1/zz_generated.deepcopy.go index a10c44e86..5ff1a18e0 100644 --- a/apis/apiextensions/v1beta1/zz_generated.deepcopy.go +++ b/apis/apiextensions/v1beta1/zz_generated.deepcopy.go @@ -445,6 +445,11 @@ func (in *EnvironmentConfiguration) DeepCopyInto(out *EnvironmentConfiguration) (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Policy != nil { + in, out := &in.Policy, &out.Policy + *out = new(commonv1.Policy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvironmentConfiguration. @@ -542,6 +547,11 @@ func (in *EnvironmentSourceReference) DeepCopy() *EnvironmentSourceReference { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EnvironmentSourceSelector) DeepCopyInto(out *EnvironmentSourceSelector) { *out = *in + if in.MaxMatch != nil { + in, out := &in.MaxMatch, &out.MaxMatch + *out = new(uint64) + **out = **in + } if in.MatchLabels != nil { in, out := &in.MatchLabels, &out.MatchLabels *out = make([]EnvironmentSourceSelectorLabelMatcher, len(*in)) diff --git a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml index 10f024202..95cd151cc 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml @@ -95,8 +95,7 @@ spec: - name type: object selector: - description: Selector selects one EnvironmentConfig via - labels. + description: Selector selects EnvironmentConfig(s) via labels. properties: matchLabels: description: MatchLabels ensures an object with matching @@ -128,6 +127,29 @@ spec: - key type: object type: array + maxMatch: + description: MaxMatch specifies the number of extracted + EnvironmentConfigs in multi mode, extracts all if + nil. + format: int64 + type: integer + mode: + default: Single + description: 'Mode specifies retrieval strategy: "single" + or "multiple".' + enum: + - Single + - Multiple + type: string + sortByFieldPath: + default: metadata.name + description: SortByFieldPath is the path to the field + based on which list of EnvironmentConfigs is alphabetically + sorted. + type: string + required: + - mode + - sortByFieldPath type: object type: default: Reference @@ -447,6 +469,33 @@ spec: type: string type: object type: array + policy: + description: Policy represents the Resolve and Resolution policies + which apply to all EnvironmentSourceReferences in EnvironmentConfigs + list. + properties: + resolution: + default: Required + description: Resolution specifies whether resolution of this + reference is required. The default is 'Required', which + means the reconcile will fail if the reference cannot be + resolved. 'Optional' means this reference will be a no-op + if it cannot be resolved. + enum: + - Required + - Optional + type: string + resolve: + description: Resolve specifies when this reference should + be resolved. The default is 'IfNotPresent', which will attempt + to resolve the reference only when the corresponding field + is not present. Use 'Always' to resolve the reference on + every reconcile. + enum: + - Always + - IfNotPresent + type: string + type: object type: object functions: description: Functions is list of Composition Functions that will @@ -1527,8 +1576,7 @@ spec: - name type: object selector: - description: Selector selects one EnvironmentConfig via - labels. + description: Selector selects EnvironmentConfig(s) via labels. properties: matchLabels: description: MatchLabels ensures an object with matching @@ -1560,6 +1608,29 @@ spec: - key type: object type: array + maxMatch: + description: MaxMatch specifies the number of extracted + EnvironmentConfigs in multi mode, extracts all if + nil. + format: int64 + type: integer + mode: + default: Single + description: 'Mode specifies retrieval strategy: "single" + or "multiple".' + enum: + - Single + - Multiple + type: string + sortByFieldPath: + default: metadata.name + description: SortByFieldPath is the path to the field + based on which list of EnvironmentConfigs is alphabetically + sorted. + type: string + required: + - mode + - sortByFieldPath type: object type: default: Reference @@ -1879,6 +1950,26 @@ spec: type: string type: object type: array + policy: + description: Policy represents the Resolve and Resolution policies + which apply to all EnvironmentSourceReferences in EnvironmentConfigs + list. + properties: + resolution: + description: Resolution specifies whether resolution of this + reference is required. The default is 'Required', which + means the reconcile will fail if the reference cannot be + resolved. 'Optional' means this reference will be a no-op + if it cannot be resolved. + type: string + resolve: + description: Resolve specifies when this reference should + be resolved. The default is 'IfNotPresent', which will attempt + to resolve the reference only when the corresponding field + is not present. Use 'Always' to resolve the reference on + every reconcile. + type: string + type: object type: object functions: description: Functions is list of Composition Functions that will diff --git a/cluster/crds/apiextensions.crossplane.io_compositions.yaml b/cluster/crds/apiextensions.crossplane.io_compositions.yaml index a0f0c8d5a..90df5819d 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositions.yaml @@ -92,8 +92,7 @@ spec: - name type: object selector: - description: Selector selects one EnvironmentConfig via - labels. + description: Selector selects EnvironmentConfig(s) via labels. properties: matchLabels: description: MatchLabels ensures an object with matching @@ -125,6 +124,29 @@ spec: - key type: object type: array + maxMatch: + description: MaxMatch specifies the number of extracted + EnvironmentConfigs in multi mode, extracts all if + nil. + format: int64 + type: integer + mode: + default: Single + description: 'Mode specifies retrieval strategy: "single" + or "multiple".' + enum: + - Single + - Multiple + type: string + sortByFieldPath: + default: metadata.name + description: SortByFieldPath is the path to the field + based on which list of EnvironmentConfigs is alphabetically + sorted. + type: string + required: + - mode + - sortByFieldPath type: object type: default: Reference @@ -444,6 +466,33 @@ spec: type: string type: object type: array + policy: + description: Policy represents the Resolve and Resolution policies + which apply to all EnvironmentSourceReferences in EnvironmentConfigs + list. + properties: + resolution: + default: Required + description: Resolution specifies whether resolution of this + reference is required. The default is 'Required', which + means the reconcile will fail if the reference cannot be + resolved. 'Optional' means this reference will be a no-op + if it cannot be resolved. + enum: + - Required + - Optional + type: string + resolve: + description: Resolve specifies when this reference should + be resolved. The default is 'IfNotPresent', which will attempt + to resolve the reference only when the corresponding field + is not present. Use 'Always' to resolve the reference on + every reconcile. + enum: + - Always + - IfNotPresent + type: string + type: object type: object functions: description: "Functions is list of Composition Functions that will diff --git a/internal/controller/apiextensions/composite/environment/fetcher.go b/internal/controller/apiextensions/composite/environment/fetcher.go index fa112b244..b36b62d3a 100644 --- a/internal/controller/apiextensions/composite/environment/fetcher.go +++ b/internal/controller/apiextensions/composite/environment/fetcher.go @@ -50,7 +50,7 @@ func NewNilEnvironmentFetcher() *NilEnvironmentFetcher { type NilEnvironmentFetcher struct{} // Fetch always returns nil. -func (f *NilEnvironmentFetcher) Fetch(_ context.Context, _ resource.Composite) (*Environment, error) { +func (f *NilEnvironmentFetcher) Fetch(_ context.Context, _ resource.Composite, _ bool) (*Environment, error) { return nil, nil } @@ -77,7 +77,7 @@ type APIEnvironmentFetcher struct { // // Note: The `.Data` path is trimmed from the result so its necessary to include // it in patches. -func (f *APIEnvironmentFetcher) Fetch(ctx context.Context, cr resource.Composite) (*Environment, error) { +func (f *APIEnvironmentFetcher) Fetch(ctx context.Context, cr resource.Composite, required bool) (*Environment, error) { var env *Environment // Return an empty environment if the XR references no EnvironmentConfigs. @@ -89,7 +89,7 @@ func (f *APIEnvironmentFetcher) Fetch(ctx context.Context, cr resource.Composite } } else { var err error - env, err = f.fetchEnvironment(ctx, cr) + env, err = f.fetchEnvironment(ctx, cr, required) if err != nil { return nil, err } @@ -104,7 +104,7 @@ func (f *APIEnvironmentFetcher) Fetch(ctx context.Context, cr resource.Composite return env, nil } -func (f *APIEnvironmentFetcher) fetchEnvironment(ctx context.Context, cr resource.Composite) (*Environment, error) { +func (f *APIEnvironmentFetcher) fetchEnvironment(ctx context.Context, cr resource.Composite, required bool) (*Environment, error) { refs := cr.GetEnvironmentConfigReferences() loadedConfigs := []v1alpha1.EnvironmentConfig{} for _, ref := range refs { @@ -112,8 +112,13 @@ func (f *APIEnvironmentFetcher) fetchEnvironment(ctx context.Context, cr resourc nn := types.NamespacedName{ Name: ref.Name, } - if err := f.kube.Get(ctx, nn, &config); err != nil { - return nil, errors.Wrap(err, errGetEnvironmentConfig) + err := f.kube.Get(ctx, nn, &config) + if err != nil { + // skip if resolution policy is optional + if required { + return nil, errors.Wrap(err, errGetEnvironmentConfig) + } + continue } loadedConfigs = append(loadedConfigs, config) } diff --git a/internal/controller/apiextensions/composite/environment/fetcher_test.go b/internal/controller/apiextensions/composite/environment/fetcher_test.go index 0dbc8e245..f87a04794 100644 --- a/internal/controller/apiextensions/composite/environment/fetcher_test.go +++ b/internal/controller/apiextensions/composite/environment/fetcher_test.go @@ -124,8 +124,9 @@ func TestFetch(t *testing.T) { } type args struct { - kube client.Client - cr *fake.Composite + kube client.Client + cr *fake.Composite + required bool } type want struct { env *Environment @@ -208,17 +209,33 @@ func TestFetch(t *testing.T) { corev1.ObjectReference{Name: "a"}, ), ), + required: true, }, want: want{ err: errors.Wrapf(errBoom, errGetEnvironmentConfig), }, }, + "NoErrorOnKubeGetErrorIfResolutionNotRequired": { + reason: "It should omit EnvironmentConfig if getting a EnvironmentConfig from a reference fails", + args: args{ + kube: &test.MockClient{ + MockGet: test.NewMockGetFn(errBoom), + }, + cr: composite( + withEnvironmentRefs(), + ), + required: false, + }, + want: want{ + env: makeEnvironment(map[string]interface{}{}), + }, + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { f := NewAPIEnvironmentFetcher(tc.args.kube) - got, err := f.Fetch(context.Background(), tc.args.cr) + got, err := f.Fetch(context.Background(), tc.args.cr, tc.args.required) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { t.Errorf("\n%s\nr.Reconcile(...): -want error, +got error:\n%s", tc.reason, diff) diff --git a/internal/controller/apiextensions/composite/environment/selector.go b/internal/controller/apiextensions/composite/environment/selector.go index 8401d7b53..8ddb18524 100644 --- a/internal/controller/apiextensions/composite/environment/selector.go +++ b/internal/controller/apiextensions/composite/environment/selector.go @@ -19,6 +19,8 @@ package environment import ( "context" "fmt" + "reflect" + "sort" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -38,9 +40,11 @@ const ( errListEnvironmentConfigs = "failed to list environments" errListEnvironmentConfigsNoResult = "no EnvironmentConfig found that matches labels" errFmtInvalidEnvironmentSourceType = "invalid source type '%s'" - - errFmtInvalidLabelMatcherType = "invalid label matcher type '%s'" - errFmtRequiredField = "%s is required by type %s" + errFmtInvalidLabelMatcherType = "invalid label matcher type '%s'" + errFmtRequiredField = "%s is required by type %s" + errUnknownSelectorMode = "unknown mode '%s'" + errSortNotMatchingTypes = "not matching types: %T : %T" + errSortUnknownType = "unexpected type %T" ) // NewNoopEnvironmentSelector creates a new NoopEnvironmentSelector. @@ -71,25 +75,33 @@ type APIEnvironmentSelector struct { // SelectEnvironment for cr using the configuration defined in comp. // The computed list of EnvironmentConfig references will be stored in cr. func (s *APIEnvironmentSelector) SelectEnvironment(ctx context.Context, cr resource.Composite, rev *v1.CompositionRevision) error { - // noop if EnvironmentConfig references are already computed - if len(cr.GetEnvironmentConfigReferences()) > 0 { - return nil - } - if rev.Spec.Environment == nil || rev.Spec.Environment.EnvironmentConfigs == nil { + + if rev.Spec.Environment.IsNoop(cr.GetEnvironmentConfigReferences()) { return nil } refs := make([]corev1.ObjectReference, len(rev.Spec.Environment.EnvironmentConfigs)) + idx := 0 for i, src := range rev.Spec.Environment.EnvironmentConfigs { switch src.Type { case v1.EnvironmentSourceTypeReference: - refs[i] = s.buildEnvironmentConfigRefFromRef(src.Ref) + refs = append( + refs[:idx], + s.buildEnvironmentConfigRefFromRef(src.Ref), + ) + idx++ case v1.EnvironmentSourceTypeSelector: - r, err := s.buildEnvironmentConfigRefFromSelector(ctx, cr, src.Selector) + + ec, err := s.lookUpConfigs(ctx, cr, src.Selector.MatchLabels) + if err != nil { + return errors.Wrapf(err, errFmtReferenceEnvironmentConfig, i) + } + r, err := s.buildEnvironmentConfigRefFromSelector(ec, src.Selector) if err != nil { return errors.Wrapf(err, errFmtReferenceEnvironmentConfig, i) } - refs[i] = r + refs = append(refs[:idx], r...) + idx += len(r) default: return errors.Errorf(errFmtInvalidEnvironmentSourceType, string(src.Type)) } @@ -106,28 +118,127 @@ func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromRef(ref *v1.Enviro } } -func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(ctx context.Context, cr resource.Composite, selector *v1.EnvironmentSourceSelector) (corev1.ObjectReference, error) { - matchLabels := make(client.MatchingLabels, len(selector.MatchLabels)) - for i, m := range selector.MatchLabels { +func (s *APIEnvironmentSelector) lookUpConfigs(ctx context.Context, cr resource.Composite, ml []v1.EnvironmentSourceSelectorLabelMatcher) (*v1alpha1.EnvironmentConfigList, error) { + matchLabels := make(client.MatchingLabels, len(ml)) + for i, m := range ml { val, err := ResolveLabelValue(m, cr) if err != nil { - return corev1.ObjectReference{}, errors.Wrapf(err, errFmtResolveLabelValue, i) + return nil, errors.Wrapf(err, errFmtResolveLabelValue, i) } matchLabels[m.Key] = val } res := &v1alpha1.EnvironmentConfigList{} if err := s.kube.List(ctx, res, matchLabels); err != nil { - return corev1.ObjectReference{}, errors.Wrap(err, errListEnvironmentConfigs) + return nil, errors.Wrap(err, errListEnvironmentConfigs) } - if len(res.Items) == 0 { - return corev1.ObjectReference{}, errors.New(errListEnvironmentConfigsNoResult) + return res, nil +} + +func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(cl *v1alpha1.EnvironmentConfigList, selector *v1.EnvironmentSourceSelector) ([]corev1.ObjectReference, error) { + + ec := make([]v1alpha1.EnvironmentConfig, 0) + + switch { + case len(cl.Items) == 0: + return []corev1.ObjectReference{}, nil + + case selector.Mode == v1.EnvironmentSourceSelectorSingleMode: + err := sortConfigs(cl.Items, selector.SortByFieldPath) + if err != nil { + return []corev1.ObjectReference{}, err + } + ec = append(ec, cl.Items[0]) + + case selector.Mode == v1.EnvironmentSourceSelectorMultiMode: + err := sortConfigs(cl.Items, selector.SortByFieldPath) + if err != nil { + return []corev1.ObjectReference{}, err + } + + if selector.MaxMatch != nil { + ec = append(ec, cl.Items[:*selector.MaxMatch]...) + } else { + ec = append(ec, cl.Items...) + } + + default: + return []corev1.ObjectReference{}, errors.Errorf(errUnknownSelectorMode, selector.Mode) } - envConfig := res.Items[0] - return corev1.ObjectReference{ - Name: envConfig.Name, - Kind: v1alpha1.EnvironmentConfigKind, - APIVersion: v1alpha1.SchemeGroupVersion.String(), - }, nil + + envConfigs := make([]corev1.ObjectReference, len(ec)) + for i, v := range ec { + envConfigs[i] = corev1.ObjectReference{ + Name: v.Name, + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + } + } + + return envConfigs, nil +} + +type sortPair struct { + ec v1alpha1.EnvironmentConfig + obj map[string]interface{} +} + +//nolint:gocyclo // tbd +func sortConfigs(ec []v1alpha1.EnvironmentConfig, f string) error { + + var err error + + p := make([]sortPair, len(ec)) + + for i := 0; i < len(ec); i++ { + m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ec[i]) + if err != nil { + return err + } + p[i] = sortPair{ + ec: ec[i], + obj: m, + } + } + + sort.Slice(p, func(i, j int) bool { + if err != nil { + return false + } + v1, e := fieldpath.Pave(p[i].obj).GetValue(f) + if e != nil { + err = e + return false + } + v2, e := fieldpath.Pave(p[j].obj).GetValue(f) + if err != nil { + err = e + return false + } + + vt1 := reflect.TypeOf(v1).Kind() + vt2 := reflect.TypeOf(v2).Kind() + switch { + case vt1 == reflect.Float64 && vt2 == reflect.Float64: + return v1.(float64) < v2.(float64) + case vt1 == reflect.Int64 && vt2 == reflect.Int64: + return v1.(int64) < v2.(int64) + case vt1 == reflect.String && vt2 == reflect.String: + return v1.(string) < v2.(string) + case vt1 != vt2: + err = errors.Errorf(errSortNotMatchingTypes, v1, v2) + default: + err = errors.Errorf(errSortUnknownType, v1) + } + return false + }) + + if err != nil { + return err + } + for i := 0; i < len(ec); i++ { + ec[i] = p[i].ec + } + return nil } // ResolveLabelValue from a EnvironmentSourceSelectorLabelMatcher and an Object. diff --git a/internal/controller/apiextensions/composite/environment/selector_test.go b/internal/controller/apiextensions/composite/environment/selector_test.go index 207614ce4..4b2e524d2 100644 --- a/internal/controller/apiextensions/composite/environment/selector_test.go +++ b/internal/controller/apiextensions/composite/environment/selector_test.go @@ -17,11 +17,14 @@ package environment import ( "context" + "encoding/json" + "fmt" "testing" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" + extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" @@ -75,6 +78,18 @@ func TestSelect(t *testing.T) { } } + makeJSON := func(m map[string]interface{}) map[string]extv1.JSON { + raw, err := json.Marshal(m) + if err != nil { + t.Fatal(err) + } + res := map[string]extv1.JSON{} + if err := json.Unmarshal(raw, &res); err != nil { + t.Fatal(err) + } + return res + } + cases := map[string]struct { reason string args args @@ -145,8 +160,8 @@ func TestSelect(t *testing.T) { ), }, }, - "RefForLabelSelectedObject": { - reason: "It should create a name reference for the first selected EnvironmentConfig that matches the labels.", + "RefForLabelSelectedObjects": { + reason: "It should create a name reference for selected EnvironmentConfigs that match the labels.", args: args{ kube: &test.MockClient{ MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { @@ -154,7 +169,18 @@ func TestSelect(t *testing.T) { list.Items = []v1alpha1.EnvironmentConfig{ { ObjectMeta: metav1.ObjectMeta{ - Name: "test", + Name: "test-1", + Labels: map[string]string{ + "foo": "bar", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + Labels: map[string]string{ + "foo": "bar", + }, }, }, } @@ -163,7 +189,6 @@ func TestSelect(t *testing.T) { }, cr: composite( withName("test-composite"), - withEnvironmentRefs(environmentConfigRef("test")), ), rev: &v1.CompositionRevision{ Spec: v1.CompositionRevisionSpec{ @@ -172,6 +197,8 @@ func TestSelect(t *testing.T) { { Type: v1.EnvironmentSourceTypeSelector, Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "metadata.name", MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, @@ -189,7 +216,7 @@ func TestSelect(t *testing.T) { want: want{ cr: composite( withName("test-composite"), - withEnvironmentRefs(environmentConfigRef("test")), + withEnvironmentRefs(environmentConfigRef("test-1"), environmentConfigRef("test-2")), ), }, }, @@ -223,6 +250,7 @@ func TestSelect(t *testing.T) { { Type: v1.EnvironmentSourceTypeSelector, Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorSingleMode, MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeFromCompositeFieldPath, @@ -253,21 +281,19 @@ func TestSelect(t *testing.T) { list.Items = []v1alpha1.EnvironmentConfig{ { ObjectMeta: metav1.ObjectMeta{ - Name: "test", + Name: "test-1", }, }, { ObjectMeta: metav1.ObjectMeta{ - Name: "not-this-one", + Name: "test-not-this-one", }, }, } return nil }), }, - cr: composite( - withEnvironmentRefs(environmentConfigRef("test")), - ), + cr: composite(), rev: &v1.CompositionRevision{ Spec: v1.CompositionRevisionSpec{ Environment: &v1.EnvironmentConfiguration{ @@ -275,8 +301,11 @@ func TestSelect(t *testing.T) { { Type: v1.EnvironmentSourceTypeSelector, Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorSingleMode, + SortByFieldPath: "metadata.name", MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, Key: "foo", Value: pointer.String("bar"), }, @@ -290,7 +319,7 @@ func TestSelect(t *testing.T) { }, want: want{ cr: composite( - withEnvironmentRefs(environmentConfigRef("test")), + withEnvironmentRefs(environmentConfigRef("test-1")), ), }, }, @@ -368,8 +397,8 @@ func TestSelect(t *testing.T) { err: errors.Wrapf(errors.Wrap(errBoom, errListEnvironmentConfigs), errFmtReferenceEnvironmentConfig, 0), }, }, - "ErrorOnKubeListEmpty": { - reason: "It should return an error if kube.List returns an empty list.", + "NoReferenceOnKubeListEmpty": { + reason: "It should return an empty list of references if kube.List returns an empty list.", args: args{ kube: &test.MockClient{ MockList: test.NewMockListFn(nil), @@ -398,9 +427,8 @@ func TestSelect(t *testing.T) { }, want: want{ cr: composite( - withEnvironmentRefs(), + withEnvironmentRefs([]corev1.ObjectReference{}...), ), - err: errors.Wrapf(errors.New(errListEnvironmentConfigsNoResult), errFmtReferenceEnvironmentConfig, 0), }, }, "ErrorOnInvalidLabelValueFieldPath": { @@ -438,6 +466,561 @@ func TestSelect(t *testing.T) { err: errors.Wrapf(errors.Wrapf(errors.New("wrong: no such field"), errFmtResolveLabelValue, 0), errFmtReferenceEnvironmentConfig, 0), }, }, + "AllRefsSortedInMultiMode": { + reason: "It should return complete list of references sorted by metadata.name", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-4", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-3", + }, + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "metadata.name", + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs([]corev1.ObjectReference{ + { + Name: "test-1", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-2", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-3", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + Name: "test-4", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + }...), + ), + }, + }, + "MaxMatchRefsSortedInMultiMode": { + reason: "It should return limited list of references sorted by specified annotation", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + Annotations: map[string]string{ + "sort.by/weight": "2", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + Annotations: map[string]string{ + "sort.by/weight": "1", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-4", + Annotations: map[string]string{ + "sort.by/weight": "4", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-3", + Annotations: map[string]string{ + "sort.by/weight": "3", + }, + }, + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "metadata.annotations[sort.by/weight]", + MaxMatch: pointer.Uint64(3), + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs([]corev1.ObjectReference{ + { + Name: "test-1", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-2", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-3", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + }...), + ), + }, + }, + "MaxMatchRefsSortedByFloatInMultiMode": { + reason: "It should return limited list of references sorted by float values", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + Data: makeJSON( + map[string]interface{}{ + "float/weight": float64(1.2), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + Data: makeJSON( + map[string]interface{}{ + "float/weight": float64(1.1), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-4", + }, + Data: makeJSON( + map[string]interface{}{ + "float/weight": float64(1.4), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-3", + }, + Data: makeJSON( + map[string]interface{}{ + "float/weight": float64(1.3), + }, + ), + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "data[float/weight]", + MaxMatch: pointer.Uint64(3), + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs([]corev1.ObjectReference{ + { + Name: "test-1", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-2", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-3", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + }...), + ), + }, + }, + "MaxMatchRefsSortedByIntInMultiMode": { + reason: "It should return limited list of references sorted by int values", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(2), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(1), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-4", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(4), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-3", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(3), + }, + ), + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "data[int/weight]", + MaxMatch: pointer.Uint64(3), + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs([]corev1.ObjectReference{ + { + Name: "test-1", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-2", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + { + + Name: "test-3", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, + }...), + ), + }, + }, + "ErrSelectOnNotMatchingType": { + reason: "It should return when types of copared values dont match", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": float64(2.1), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(1), + }, + ), + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "data[int/weight]", + MaxMatch: pointer.Uint64(3), + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs(), + ), + err: errors.Wrap(fmt.Errorf("not matching types: int64 : float64"), "failed to build reference at index 0"), + }, + }, + "ErrSelectOnUnexpectedType": { + reason: "It should return error when compared values have unexpected types", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": true, + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": true, + }, + ), + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "data[int/weight]", + MaxMatch: pointer.Uint64(3), + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs(), + ), + err: errors.Wrap(fmt.Errorf("unexpected type bool"), "failed to build reference at index 0"), + }, + }, + "ErrSelectOnInvalidFieldPath": { + reason: "It should return error on invalid field path", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + SortByFieldPath: "metadata.annotations[int/weight]", + MaxMatch: pointer.Uint64(3), + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs(), + ), + err: errors.Wrap(fmt.Errorf("metadata.annotations: no such field"), "failed to build reference at index 0"), + }, + }, } for name, tc := range cases { diff --git a/internal/controller/apiextensions/composite/reconciler.go b/internal/controller/apiextensions/composite/reconciler.go index 6ae9d2662..416d4380c 100644 --- a/internal/controller/apiextensions/composite/reconciler.go +++ b/internal/controller/apiextensions/composite/reconciler.go @@ -150,16 +150,16 @@ func (fn EnvironmentSelectorFn) SelectEnvironment(ctx context.Context, cr resour // An EnvironmentFetcher fetches an appropriate environment for the supplied // composite resource. type EnvironmentFetcher interface { - Fetch(ctx context.Context, cr resource.Composite) (*env.Environment, error) + Fetch(ctx context.Context, cr resource.Composite, required bool) (*env.Environment, error) } // An EnvironmentFetcherFn fetches an appropriate environment for the supplied // composite resource. -type EnvironmentFetcherFn func(ctx context.Context, cr resource.Composite) (*env.Environment, error) +type EnvironmentFetcherFn func(ctx context.Context, cr resource.Composite, required bool) (*env.Environment, error) // Fetch an appropriate environment for the supplied Composite resource. -func (fn EnvironmentFetcherFn) Fetch(ctx context.Context, cr resource.Composite) (*env.Environment, error) { - return fn(ctx, cr) +func (fn EnvironmentFetcherFn) Fetch(ctx context.Context, cr resource.Composite, required bool) (*env.Environment, error) { + return fn(ctx, cr, required) } // A Configurator configures a composite resource using its composition. @@ -559,7 +559,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{}, err } - env, err := r.environment.Fetch(ctx, xr) + env, err := r.environment.Fetch(ctx, xr, rev.Spec.Environment.IsRequired()) if err != nil { log.Debug(errFetchEnvironment, "error", err) err = errors.Wrap(err, errFetchEnvironment) diff --git a/internal/controller/apiextensions/composite/reconciler_test.go b/internal/controller/apiextensions/composite/reconciler_test.go index ed7cc2dc7..49a0c7341 100644 --- a/internal/controller/apiextensions/composite/reconciler_test.go +++ b/internal/controller/apiextensions/composite/reconciler_test.go @@ -381,7 +381,7 @@ func TestReconcile(t *testing.T) { })), WithCompositionRevisionValidator(CompositionRevisionValidatorFn(func(_ *v1.CompositionRevision) error { return nil })), WithConfigurator(ConfiguratorFn(func(ctx context.Context, cr resource.Composite, rev *v1.CompositionRevision) error { return nil })), - WithEnvironmentFetcher(EnvironmentFetcherFn(func(ctx context.Context, cr resource.Composite) (*env.Environment, error) { + WithEnvironmentFetcher(EnvironmentFetcherFn(func(ctx context.Context, cr resource.Composite, required bool) (*env.Environment, error) { return nil, errBoom })), WithCompositionUpdatePolicySelector(CompositionUpdatePolicySelectorFn(func(ctx context.Context, cr resource.Composite) error { return nil })), From 503fc4562ea8bee194ab42864d62bde10dd91c8b Mon Sep 17 00:00:00 2001 From: Matej Ohradzansky Date: Sat, 24 Jun 2023 00:13:54 +0200 Subject: [PATCH 057/148] address review comments Signed-off-by: Matej Ohradzansky --- .../v1/composition_environment.go | 16 +-- .../v1/composition_environment_test.go | 14 +-- .../zz_generated.composition_environment.go | 16 +-- ...ns.crossplane.io_compositionrevisions.yaml | 16 +-- ...extensions.crossplane.io_compositions.yaml | 8 +- .../composite/environment/selector.go | 12 +- .../composite/environment/selector_test.go | 109 +++++++++++++++--- 7 files changed, 135 insertions(+), 56 deletions(-) diff --git a/apis/apiextensions/v1/composition_environment.go b/apis/apiextensions/v1/composition_environment.go index 941bd74f5..8ba174553 100644 --- a/apis/apiextensions/v1/composition_environment.go +++ b/apis/apiextensions/v1/composition_environment.go @@ -71,18 +71,18 @@ func (e *EnvironmentConfiguration) Validate() field.ErrorList { return errs } -// IsNoop specifies whether EnvironmentConfiguration should be resolved or not. -func (e *EnvironmentConfiguration) IsNoop(currentRefs []corev1.ObjectReference) bool { +// ShouldResolve specifies whether EnvironmentConfiguration should be resolved or not. +func (e *EnvironmentConfiguration) ShouldResolve(currentRefs []corev1.ObjectReference) bool { if e == nil || len(e.EnvironmentConfigs) == 0 { - return true + return false } if len(currentRefs) == 0 { - return false + return true } - // currentRefs is non-empty list -> trigger update only if policy.resolve is Always - return !e.Policy.IsResolvePolicyAlways() + + return e.Policy.IsResolvePolicyAlways() } // IsRequired specifies whether EnvironmentConfiguration is required or not. @@ -181,12 +181,12 @@ const ( // An EnvironmentSourceSelector selects an EnvironmentConfig via labels. type EnvironmentSourceSelector struct { - // Mode specifies retrieval strategy: "single" or "multiple". + // Mode specifies retrieval strategy: "Single" or "Multiple". // +kubebuilder:validation:Enum=Single;Multiple // +kubebuilder:default=Single Mode EnvironmentSourceSelectorModeType `json:"mode"` - // MaxMatch specifies the number of extracted EnvironmentConfigs in multi mode, extracts all if nil. + // MaxMatch specifies the number of extracted EnvironmentConfigs in Multiple mode, extracts all if nil. MaxMatch *uint64 `json:"maxMatch,omitempty"` // SortByFieldPath is the path to the field based on which list of EnvironmentConfigs is alphabetically sorted. diff --git a/apis/apiextensions/v1/composition_environment_test.go b/apis/apiextensions/v1/composition_environment_test.go index bf9c08c82..10f0baeba 100644 --- a/apis/apiextensions/v1/composition_environment_test.go +++ b/apis/apiextensions/v1/composition_environment_test.go @@ -79,7 +79,7 @@ func TestEnvironmentPatchValidate(t *testing.T) { } } -func TestEnvironmentIsNoop(t *testing.T) { +func TestEnvironmentShouldResolve(t *testing.T) { withResolvePolicy := func() *v1.ResolvePolicy { p := v1.ResolvePolicyAlways @@ -104,7 +104,7 @@ func TestEnvironmentIsNoop(t *testing.T) { }, refs: []corev1.ObjectReference{{}}, }, - want: true, + want: false, }, "ResolveWhenNoRefs": { reason: "Should resolve when no refs are held", @@ -114,7 +114,7 @@ func TestEnvironmentIsNoop(t *testing.T) { }, refs: []corev1.ObjectReference{}, }, - want: false, + want: true, }, "ResolveWhenPolicyAlways": { reason: "Should resolve when resolve policy is Always", @@ -132,7 +132,7 @@ func TestEnvironmentIsNoop(t *testing.T) { {}, }, }, - want: false, + want: true, }, "DontResolveWhenPolicyNotAlways": { reason: "Should not resolve when resolve policy is not Always", @@ -147,16 +147,16 @@ func TestEnvironmentIsNoop(t *testing.T) { {}, }, }, - want: true, + want: false, }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { - got := tc.args.ec.IsNoop(tc.args.refs) + got := tc.args.ec.ShouldResolve(tc.args.refs) if diff := cmp.Diff(tc.want, got); diff != "" { - t.Errorf("%s\nIsNoop(...): -want, +got:\n%s", tc.reason, diff) + t.Errorf("%s\nShouldResolve(...): -want, +got:\n%s", tc.reason, diff) } }) } diff --git a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go index 4ea3f76ab..aad1c9fbb 100644 --- a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go +++ b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go @@ -73,18 +73,18 @@ func (e *EnvironmentConfiguration) Validate() field.ErrorList { return errs } -// IsNoop specifies whether EnvironmentConfiguration should be resolved or not. -func (e *EnvironmentConfiguration) IsNoop(currentRefs []corev1.ObjectReference) bool { +// ShouldResolve specifies whether EnvironmentConfiguration should be resolved or not. +func (e *EnvironmentConfiguration) ShouldResolve(currentRefs []corev1.ObjectReference) bool { if e == nil || len(e.EnvironmentConfigs) == 0 { - return true + return false } if len(currentRefs) == 0 { - return false + return true } - // currentRefs is non-empty list -> trigger update only if policy.resolve is Always - return !e.Policy.IsResolvePolicyAlways() + + return e.Policy.IsResolvePolicyAlways() } // IsRequired specifies whether EnvironmentConfiguration is required or not. @@ -183,12 +183,12 @@ const ( // An EnvironmentSourceSelector selects an EnvironmentConfig via labels. type EnvironmentSourceSelector struct { - // Mode specifies retrieval strategy: "single" or "multiple". + // Mode specifies retrieval strategy: "Single" or "Multiple". // +kubebuilder:validation:Enum=Single;Multiple // +kubebuilder:default=Single Mode EnvironmentSourceSelectorModeType `json:"mode"` - // MaxMatch specifies the number of extracted EnvironmentConfigs in multi mode, extracts all if nil. + // MaxMatch specifies the number of extracted EnvironmentConfigs in Multiple mode, extracts all if nil. MaxMatch *uint64 `json:"maxMatch,omitempty"` // SortByFieldPath is the path to the field based on which list of EnvironmentConfigs is alphabetically sorted. diff --git a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml index 95cd151cc..77e2007a1 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml @@ -129,14 +129,14 @@ spec: type: array maxMatch: description: MaxMatch specifies the number of extracted - EnvironmentConfigs in multi mode, extracts all if - nil. + EnvironmentConfigs in Multiple mode, extracts all + if nil. format: int64 type: integer mode: default: Single - description: 'Mode specifies retrieval strategy: "single" - or "multiple".' + description: 'Mode specifies retrieval strategy: "Single" + or "Multiple".' enum: - Single - Multiple @@ -1610,14 +1610,14 @@ spec: type: array maxMatch: description: MaxMatch specifies the number of extracted - EnvironmentConfigs in multi mode, extracts all if - nil. + EnvironmentConfigs in Multiple mode, extracts all + if nil. format: int64 type: integer mode: default: Single - description: 'Mode specifies retrieval strategy: "single" - or "multiple".' + description: 'Mode specifies retrieval strategy: "Single" + or "Multiple".' enum: - Single - Multiple diff --git a/cluster/crds/apiextensions.crossplane.io_compositions.yaml b/cluster/crds/apiextensions.crossplane.io_compositions.yaml index 90df5819d..9347d9c2f 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositions.yaml @@ -126,14 +126,14 @@ spec: type: array maxMatch: description: MaxMatch specifies the number of extracted - EnvironmentConfigs in multi mode, extracts all if - nil. + EnvironmentConfigs in Multiple mode, extracts all + if nil. format: int64 type: integer mode: default: Single - description: 'Mode specifies retrieval strategy: "single" - or "multiple".' + description: 'Mode specifies retrieval strategy: "Single" + or "Multiple".' enum: - Single - Multiple diff --git a/internal/controller/apiextensions/composite/environment/selector.go b/internal/controller/apiextensions/composite/environment/selector.go index 8ddb18524..5a9c5b14a 100644 --- a/internal/controller/apiextensions/composite/environment/selector.go +++ b/internal/controller/apiextensions/composite/environment/selector.go @@ -45,6 +45,7 @@ const ( errUnknownSelectorMode = "unknown mode '%s'" errSortNotMatchingTypes = "not matching types: %T : %T" errSortUnknownType = "unexpected type %T" + errExceededMaxMatch = "found items: %d exceed MaxMatch limit: %d" ) // NewNoopEnvironmentSelector creates a new NoopEnvironmentSelector. @@ -76,7 +77,7 @@ type APIEnvironmentSelector struct { // The computed list of EnvironmentConfig references will be stored in cr. func (s *APIEnvironmentSelector) SelectEnvironment(ctx context.Context, cr resource.Composite, rev *v1.CompositionRevision) error { - if rev.Spec.Environment.IsNoop(cr.GetEnvironmentConfigReferences()) { + if !rev.Spec.Environment.ShouldResolve(cr.GetEnvironmentConfigReferences()) { return nil } @@ -155,10 +156,13 @@ func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(cl *v1alp return []corev1.ObjectReference{}, err } - if selector.MaxMatch != nil { - ec = append(ec, cl.Items[:*selector.MaxMatch]...) - } else { + switch { + case selector.MaxMatch == nil: ec = append(ec, cl.Items...) + case len(cl.Items) <= int(*selector.MaxMatch): + ec = append(ec, cl.Items[:*selector.MaxMatch]...) + default: + return []corev1.ObjectReference{}, errors.Errorf(errExceededMaxMatch, len(cl.Items), *selector.MaxMatch) } default: diff --git a/internal/controller/apiextensions/composite/environment/selector_test.go b/internal/controller/apiextensions/composite/environment/selector_test.go index 4b2e524d2..c065e77fb 100644 --- a/internal/controller/apiextensions/composite/environment/selector_test.go +++ b/internal/controller/apiextensions/composite/environment/selector_test.go @@ -603,7 +603,6 @@ func TestSelect(t *testing.T) { Selector: &v1.EnvironmentSourceSelector{ Mode: v1.EnvironmentSourceSelectorMultiMode, SortByFieldPath: "metadata.annotations[sort.by/weight]", - MaxMatch: pointer.Uint64(3), MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, @@ -627,17 +626,20 @@ func TestSelect(t *testing.T) { APIVersion: v1alpha1.SchemeGroupVersion.String(), }, { - Name: "test-2", Kind: v1alpha1.EnvironmentConfigKind, APIVersion: v1alpha1.SchemeGroupVersion.String(), }, { - Name: "test-3", Kind: v1alpha1.EnvironmentConfigKind, APIVersion: v1alpha1.SchemeGroupVersion.String(), }, + { + Name: "test-4", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, }...), ), }, @@ -703,7 +705,6 @@ func TestSelect(t *testing.T) { Selector: &v1.EnvironmentSourceSelector{ Mode: v1.EnvironmentSourceSelectorMultiMode, SortByFieldPath: "data[float/weight]", - MaxMatch: pointer.Uint64(3), MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, @@ -727,17 +728,20 @@ func TestSelect(t *testing.T) { APIVersion: v1alpha1.SchemeGroupVersion.String(), }, { - Name: "test-2", Kind: v1alpha1.EnvironmentConfigKind, APIVersion: v1alpha1.SchemeGroupVersion.String(), }, { - Name: "test-3", Kind: v1alpha1.EnvironmentConfigKind, APIVersion: v1alpha1.SchemeGroupVersion.String(), }, + { + Name: "test-4", + Kind: v1alpha1.EnvironmentConfigKind, + APIVersion: v1alpha1.SchemeGroupVersion.String(), + }, }...), ), }, @@ -769,16 +773,6 @@ func TestSelect(t *testing.T) { }, ), }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "test-4", - }, - Data: makeJSON( - map[string]interface{}{ - "int/weight": int64(4), - }, - ), - }, { ObjectMeta: metav1.ObjectMeta{ Name: "test-3", @@ -802,8 +796,8 @@ func TestSelect(t *testing.T) { Type: v1.EnvironmentSourceTypeSelector, Selector: &v1.EnvironmentSourceSelector{ Mode: v1.EnvironmentSourceSelectorMultiMode, - SortByFieldPath: "data[int/weight]", MaxMatch: pointer.Uint64(3), + SortByFieldPath: "data[int/weight]", MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, @@ -842,6 +836,87 @@ func TestSelect(t *testing.T) { ), }, }, + "ErrWhenFoundItemsExceedMaxMatch": { + reason: "It should return an error when the number of EnvironmentConfigs is higher than MaxMatch", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(2), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(1), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-4", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(4), + }, + ), + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-3", + }, + Data: makeJSON( + map[string]interface{}{ + "int/weight": int64(3), + }, + ), + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorMultiMode, + MaxMatch: pointer.Uint64(3), + SortByFieldPath: "data[int/weight]", + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite(), + err: errors.Wrap(fmt.Errorf("found items: 4 exceed MaxMatch limit: 3"), "failed to build reference at index 0"), + }, + }, "ErrSelectOnNotMatchingType": { reason: "It should return when types of copared values dont match", args: args{ From b661b46ca8b06694b9231acd7d0827d892957eae Mon Sep 17 00:00:00 2001 From: Matej Ohradzansky Date: Sat, 24 Jun 2023 08:31:16 +0200 Subject: [PATCH 058/148] error out if more than 1 env is found in Single mode Signed-off-by: Matej Ohradzansky --- .../composite/environment/selector.go | 9 +-- .../composite/environment/selector_test.go | 55 +++++++++++++++++-- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/internal/controller/apiextensions/composite/environment/selector.go b/internal/controller/apiextensions/composite/environment/selector.go index 5a9c5b14a..1a408d049 100644 --- a/internal/controller/apiextensions/composite/environment/selector.go +++ b/internal/controller/apiextensions/composite/environment/selector.go @@ -45,7 +45,8 @@ const ( errUnknownSelectorMode = "unknown mode '%s'" errSortNotMatchingTypes = "not matching types: %T : %T" errSortUnknownType = "unexpected type %T" - errExceededMaxMatch = "found items: %d exceed MaxMatch limit: %d" + errExceededMaxMatch = "number of found EnvironmentConfigs: %d exceed MaxMatch limit: %d" + errFoundMultipleInSingleMode = "only 1 EnvironmentConfig should be selected in Single mode, found: %d" ) // NewNoopEnvironmentSelector creates a new NoopEnvironmentSelector. @@ -144,9 +145,9 @@ func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(cl *v1alp return []corev1.ObjectReference{}, nil case selector.Mode == v1.EnvironmentSourceSelectorSingleMode: - err := sortConfigs(cl.Items, selector.SortByFieldPath) - if err != nil { - return []corev1.ObjectReference{}, err + + if len(cl.Items) != 1 { + return []corev1.ObjectReference{}, errors.Errorf(errFoundMultipleInSingleMode, len(cl.Items)) } ec = append(ec, cl.Items[0]) diff --git a/internal/controller/apiextensions/composite/environment/selector_test.go b/internal/controller/apiextensions/composite/environment/selector_test.go index c065e77fb..5220a2530 100644 --- a/internal/controller/apiextensions/composite/environment/selector_test.go +++ b/internal/controller/apiextensions/composite/environment/selector_test.go @@ -273,7 +273,53 @@ func TestSelect(t *testing.T) { }, }, "RefForFirstLabelSelectedObject": { - reason: "It should create a name reference for the first selected EnvironmentConfig that matches the labels.", + reason: "It should create a name reference for the single selected EnvironmentConfig that matches the labels.", + args: args{ + kube: &test.MockClient{ + MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { + list := obj.(*v1alpha1.EnvironmentConfigList) + list.Items = []v1alpha1.EnvironmentConfig{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + }, + } + return nil + }), + }, + cr: composite(), + rev: &v1.CompositionRevision{ + Spec: v1.CompositionRevisionSpec{ + Environment: &v1.EnvironmentConfiguration{ + EnvironmentConfigs: []v1.EnvironmentSource{ + { + Type: v1.EnvironmentSourceTypeSelector, + Selector: &v1.EnvironmentSourceSelector{ + Mode: v1.EnvironmentSourceSelectorSingleMode, + SortByFieldPath: "metadata.name", + MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ + { + Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, + Key: "foo", + Value: pointer.String("bar"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: want{ + cr: composite( + withEnvironmentRefs(environmentConfigRef("test-1")), + ), + }, + }, + "ErrorOnMultipleObjectsInSingleMode": { + reason: "It should return an error if more than 1 EnvironmentConfigs match the labels.", args: args{ kube: &test.MockClient{ MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { @@ -318,9 +364,8 @@ func TestSelect(t *testing.T) { }, }, want: want{ - cr: composite( - withEnvironmentRefs(environmentConfigRef("test-1")), - ), + cr: composite(), + err: errors.Wrap(fmt.Errorf("only 1 EnvironmentConfig should be selected in Single mode, found: 2"), "failed to build reference at index 0"), }, }, "RefsInOrder": { @@ -914,7 +959,7 @@ func TestSelect(t *testing.T) { }, want: want{ cr: composite(), - err: errors.Wrap(fmt.Errorf("found items: 4 exceed MaxMatch limit: 3"), "failed to build reference at index 0"), + err: errors.Wrap(fmt.Errorf("number of found EnvironmentConfigs: 4 exceed MaxMatch limit: 3"), "failed to build reference at index 0"), }, }, "ErrSelectOnNotMatchingType": { From 6972e749b081a081ace89a2da219094a62b0ac42 Mon Sep 17 00:00:00 2001 From: Matej Ohradzansky Date: Wed, 5 Jul 2023 13:52:26 +0200 Subject: [PATCH 059/148] adjust env config logic in Multiple mode and add validation Signed-off-by: Matej Ohradzansky --- .../v1/composition_environment.go | 23 ++++- .../zz_generated.composition_environment.go | 23 ++++- .../composite/environment/selector.go | 10 +-- .../composite/environment/selector_test.go | 83 +------------------ 4 files changed, 42 insertions(+), 97 deletions(-) diff --git a/apis/apiextensions/v1/composition_environment.go b/apis/apiextensions/v1/composition_environment.go index 8ba174553..88c9ecead 100644 --- a/apis/apiextensions/v1/composition_environment.go +++ b/apis/apiextensions/v1/composition_environment.go @@ -141,11 +141,10 @@ func (e *EnvironmentSource) Validate() *field.Error { return field.Required(field.NewPath("selector", "matchLabels"), "selector must have at least one match label") } - for i, m := range e.Selector.MatchLabels { - if err := m.Validate(); err != nil { - return errors.WrapFieldError(err, field.NewPath("selector", "matchLabels").Index(i)) - } + if err := e.Selector.Validate(); err != nil { + return errors.WrapFieldError(err, field.NewPath("selector")) } + default: return field.Invalid(field.NewPath("type"), e.Type, "invalid type") } @@ -197,6 +196,22 @@ type EnvironmentSourceSelector struct { MatchLabels []EnvironmentSourceSelectorLabelMatcher `json:"matchLabels,omitempty"` } +// Validate logically validates the EnvironmentSourceSelector. +func (e *EnvironmentSourceSelector) Validate() *field.Error { + + if e.Mode == EnvironmentSourceSelectorSingleMode && e.MaxMatch != nil { + return field.Forbidden(field.NewPath("maxMatch"), "maxMatch is not supported in Single mode") + } + + for i, m := range e.MatchLabels { + if err := m.Validate(); err != nil { + return errors.WrapFieldError(err, field.NewPath("matchLabels").Index(i)) + } + } + + return nil +} + // EnvironmentSourceSelectorLabelMatcherType specifies where the value for a // label comes from. type EnvironmentSourceSelectorLabelMatcherType string diff --git a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go index aad1c9fbb..4237452cb 100644 --- a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go +++ b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go @@ -143,11 +143,10 @@ func (e *EnvironmentSource) Validate() *field.Error { return field.Required(field.NewPath("selector", "matchLabels"), "selector must have at least one match label") } - for i, m := range e.Selector.MatchLabels { - if err := m.Validate(); err != nil { - return errors.WrapFieldError(err, field.NewPath("selector", "matchLabels").Index(i)) - } + if err := e.Selector.Validate(); err != nil { + return errors.WrapFieldError(err, field.NewPath("selector")) } + default: return field.Invalid(field.NewPath("type"), e.Type, "invalid type") } @@ -199,6 +198,22 @@ type EnvironmentSourceSelector struct { MatchLabels []EnvironmentSourceSelectorLabelMatcher `json:"matchLabels,omitempty"` } +// Validate logically validates the EnvironmentSourceSelector. +func (e *EnvironmentSourceSelector) Validate() *field.Error { + + if e.Mode == EnvironmentSourceSelectorSingleMode && e.MaxMatch != nil { + return field.Forbidden(field.NewPath("maxMatch"), "maxMatch is not supported in Single mode") + } + + for i, m := range e.MatchLabels { + if err := m.Validate(); err != nil { + return errors.WrapFieldError(err, field.NewPath("matchLabels").Index(i)) + } + } + + return nil +} + // EnvironmentSourceSelectorLabelMatcherType specifies where the value for a // label comes from. type EnvironmentSourceSelectorLabelMatcherType string diff --git a/internal/controller/apiextensions/composite/environment/selector.go b/internal/controller/apiextensions/composite/environment/selector.go index 1a408d049..6d643affb 100644 --- a/internal/controller/apiextensions/composite/environment/selector.go +++ b/internal/controller/apiextensions/composite/environment/selector.go @@ -45,8 +45,7 @@ const ( errUnknownSelectorMode = "unknown mode '%s'" errSortNotMatchingTypes = "not matching types: %T : %T" errSortUnknownType = "unexpected type %T" - errExceededMaxMatch = "number of found EnvironmentConfigs: %d exceed MaxMatch limit: %d" - errFoundMultipleInSingleMode = "only 1 EnvironmentConfig should be selected in Single mode, found: %d" + errFoundMultipleInSingleMode = "only 1 EnvironmentConfig can be selected in Single mode, found: %d" ) // NewNoopEnvironmentSelector creates a new NoopEnvironmentSelector. @@ -157,13 +156,10 @@ func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(cl *v1alp return []corev1.ObjectReference{}, err } - switch { - case selector.MaxMatch == nil: + if selector.MaxMatch == nil { ec = append(ec, cl.Items...) - case len(cl.Items) <= int(*selector.MaxMatch): + } else { ec = append(ec, cl.Items[:*selector.MaxMatch]...) - default: - return []corev1.ObjectReference{}, errors.Errorf(errExceededMaxMatch, len(cl.Items), *selector.MaxMatch) } default: diff --git a/internal/controller/apiextensions/composite/environment/selector_test.go b/internal/controller/apiextensions/composite/environment/selector_test.go index 5220a2530..f1b061a23 100644 --- a/internal/controller/apiextensions/composite/environment/selector_test.go +++ b/internal/controller/apiextensions/composite/environment/selector_test.go @@ -365,7 +365,7 @@ func TestSelect(t *testing.T) { }, want: want{ cr: composite(), - err: errors.Wrap(fmt.Errorf("only 1 EnvironmentConfig should be selected in Single mode, found: 2"), "failed to build reference at index 0"), + err: errors.Wrap(fmt.Errorf("only 1 EnvironmentConfig can be selected in Single mode, found: 2"), "failed to build reference at index 0"), }, }, "RefsInOrder": { @@ -881,87 +881,6 @@ func TestSelect(t *testing.T) { ), }, }, - "ErrWhenFoundItemsExceedMaxMatch": { - reason: "It should return an error when the number of EnvironmentConfigs is higher than MaxMatch", - args: args{ - kube: &test.MockClient{ - MockList: test.NewMockListFn(nil, func(obj client.ObjectList) error { - list := obj.(*v1alpha1.EnvironmentConfigList) - list.Items = []v1alpha1.EnvironmentConfig{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "test-2", - }, - Data: makeJSON( - map[string]interface{}{ - "int/weight": int64(2), - }, - ), - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "test-1", - }, - Data: makeJSON( - map[string]interface{}{ - "int/weight": int64(1), - }, - ), - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "test-4", - }, - Data: makeJSON( - map[string]interface{}{ - "int/weight": int64(4), - }, - ), - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "test-3", - }, - Data: makeJSON( - map[string]interface{}{ - "int/weight": int64(3), - }, - ), - }, - } - return nil - }), - }, - cr: composite(), - rev: &v1.CompositionRevision{ - Spec: v1.CompositionRevisionSpec{ - Environment: &v1.EnvironmentConfiguration{ - EnvironmentConfigs: []v1.EnvironmentSource{ - { - Type: v1.EnvironmentSourceTypeSelector, - Selector: &v1.EnvironmentSourceSelector{ - Mode: v1.EnvironmentSourceSelectorMultiMode, - MaxMatch: pointer.Uint64(3), - SortByFieldPath: "data[int/weight]", - MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ - { - Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, - Key: "foo", - Value: pointer.String("bar"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - want: want{ - cr: composite(), - err: errors.Wrap(fmt.Errorf("number of found EnvironmentConfigs: 4 exceed MaxMatch limit: 3"), "failed to build reference at index 0"), - }, - }, "ErrSelectOnNotMatchingType": { reason: "It should return when types of copared values dont match", args: args{ From 86be83fc2ae95208e2405e7fce4863d32cfc4d7a Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Mon, 10 Jul 2023 10:26:33 +0200 Subject: [PATCH 060/148] tests: APIEnvironmentFetcher defaulting tests with required true Signed-off-by: Philippe Scorsolini --- .../composite/environment/fetcher_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/controller/apiextensions/composite/environment/fetcher_test.go b/internal/controller/apiextensions/composite/environment/fetcher_test.go index f87a04794..124fb57cb 100644 --- a/internal/controller/apiextensions/composite/environment/fetcher_test.go +++ b/internal/controller/apiextensions/composite/environment/fetcher_test.go @@ -26,6 +26,7 @@ import ( extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/crossplane/crossplane-runtime/pkg/resource/fake" @@ -126,7 +127,7 @@ func TestFetch(t *testing.T) { type args struct { kube client.Client cr *fake.Composite - required bool + required *bool } type want struct { env *Environment @@ -209,7 +210,6 @@ func TestFetch(t *testing.T) { corev1.ObjectReference{Name: "a"}, ), ), - required: true, }, want: want{ err: errors.Wrapf(errBoom, errGetEnvironmentConfig), @@ -224,7 +224,7 @@ func TestFetch(t *testing.T) { cr: composite( withEnvironmentRefs(), ), - required: false, + required: pointer.Bool(false), }, want: want{ env: makeEnvironment(map[string]interface{}{}), @@ -235,7 +235,11 @@ func TestFetch(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { f := NewAPIEnvironmentFetcher(tc.args.kube) - got, err := f.Fetch(context.Background(), tc.args.cr, tc.args.required) + required := true + if tc.args.required != nil { + required = *tc.args.required + } + got, err := f.Fetch(context.Background(), tc.args.cr, required) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { t.Errorf("\n%s\nr.Reconcile(...): -want error, +got error:\n%s", tc.reason, diff) From bd8bce8754bd923b65ca0503e5bd1e3bf46b4df6 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Mon, 10 Jul 2023 11:52:43 +0200 Subject: [PATCH 061/148] tests: add environmentRef to actually exercise code Signed-off-by: Philippe Scorsolini --- .../apiextensions/composite/environment/fetcher_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/controller/apiextensions/composite/environment/fetcher_test.go b/internal/controller/apiextensions/composite/environment/fetcher_test.go index 124fb57cb..caf267d47 100644 --- a/internal/controller/apiextensions/composite/environment/fetcher_test.go +++ b/internal/controller/apiextensions/composite/environment/fetcher_test.go @@ -222,7 +222,9 @@ func TestFetch(t *testing.T) { MockGet: test.NewMockGetFn(errBoom), }, cr: composite( - withEnvironmentRefs(), + withEnvironmentRefs( + corev1.ObjectReference{Name: "a"}, + ), ), required: pointer.Bool(false), }, From c5060ef37124618a3593d6e95433ca07fd266b92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:27:24 +0000 Subject: [PATCH 062/148] Update docker/setup-buildx-action digest to 4c0219f --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a20f0a98..9c6ba4d7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -249,7 +249,7 @@ jobs: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@2a1a44ac4aa01993040736bd95bb470da1a38365 # v2 + uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true @@ -311,7 +311,7 @@ jobs: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@2a1a44ac4aa01993040736bd95bb470da1a38365 # v2 + uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true From 9e4b5a4218428106e6d0e49160cd55c29ebfa00a Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 12 Jul 2023 19:00:35 +0200 Subject: [PATCH 063/148] chore: review Signed-off-by: Philippe Scorsolini --- .../v1/composition_environment.go | 1 - .../v1/composition_environment_test.go | 1 - .../zz_generated.composition_environment.go | 1 - .../composite/environment/selector.go | 134 +++++++++--------- .../composite/environment/selector_test.go | 11 +- 5 files changed, 70 insertions(+), 78 deletions(-) diff --git a/apis/apiextensions/v1/composition_environment.go b/apis/apiextensions/v1/composition_environment.go index 88c9ecead..b402601dd 100644 --- a/apis/apiextensions/v1/composition_environment.go +++ b/apis/apiextensions/v1/composition_environment.go @@ -144,7 +144,6 @@ func (e *EnvironmentSource) Validate() *field.Error { if err := e.Selector.Validate(); err != nil { return errors.WrapFieldError(err, field.NewPath("selector")) } - default: return field.Invalid(field.NewPath("type"), e.Type, "invalid type") } diff --git a/apis/apiextensions/v1/composition_environment_test.go b/apis/apiextensions/v1/composition_environment_test.go index 10f0baeba..6363d0690 100644 --- a/apis/apiextensions/v1/composition_environment_test.go +++ b/apis/apiextensions/v1/composition_environment_test.go @@ -80,7 +80,6 @@ func TestEnvironmentPatchValidate(t *testing.T) { } func TestEnvironmentShouldResolve(t *testing.T) { - withResolvePolicy := func() *v1.ResolvePolicy { p := v1.ResolvePolicyAlways return &p diff --git a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go index 4237452cb..01f26f0fb 100644 --- a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go +++ b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go @@ -146,7 +146,6 @@ func (e *EnvironmentSource) Validate() *field.Error { if err := e.Selector.Validate(); err != nil { return errors.WrapFieldError(err, field.NewPath("selector")) } - default: return field.Invalid(field.NewPath("type"), e.Type, "invalid type") } diff --git a/internal/controller/apiextensions/composite/environment/selector.go b/internal/controller/apiextensions/composite/environment/selector.go index 6d643affb..e07feb997 100644 --- a/internal/controller/apiextensions/composite/environment/selector.go +++ b/internal/controller/apiextensions/composite/environment/selector.go @@ -31,21 +31,20 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/resource" v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" - v1alpha1 "github.com/crossplane/crossplane/apis/apiextensions/v1alpha1" + "github.com/crossplane/crossplane/apis/apiextensions/v1alpha1" ) const ( errFmtReferenceEnvironmentConfig = "failed to build reference at index %d" errFmtResolveLabelValue = "failed to resolve value for label at index %d" errListEnvironmentConfigs = "failed to list environments" - errListEnvironmentConfigsNoResult = "no EnvironmentConfig found that matches labels" errFmtInvalidEnvironmentSourceType = "invalid source type '%s'" errFmtInvalidLabelMatcherType = "invalid label matcher type '%s'" errFmtRequiredField = "%s is required by type %s" - errUnknownSelectorMode = "unknown mode '%s'" - errSortNotMatchingTypes = "not matching types: %T : %T" - errSortUnknownType = "unexpected type %T" - errFoundMultipleInSingleMode = "only 1 EnvironmentConfig can be selected in Single mode, found: %d" + errFmtUnknownSelectorMode = "unknown mode '%s'" + errFmtSortNotMatchingTypes = "not matching types, got %[1]v (%[1]T), expected %[2]v" + errFmtSortUnknownType = "unexpected type %T" + errFmtFoundMultipleInSingleMode = "only 1 EnvironmentConfig can be selected in Single mode, found: %d" ) // NewNoopEnvironmentSelector creates a new NoopEnvironmentSelector. @@ -76,23 +75,19 @@ type APIEnvironmentSelector struct { // SelectEnvironment for cr using the configuration defined in comp. // The computed list of EnvironmentConfig references will be stored in cr. func (s *APIEnvironmentSelector) SelectEnvironment(ctx context.Context, cr resource.Composite, rev *v1.CompositionRevision) error { - if !rev.Spec.Environment.ShouldResolve(cr.GetEnvironmentConfigReferences()) { return nil } - refs := make([]corev1.ObjectReference, len(rev.Spec.Environment.EnvironmentConfigs)) - idx := 0 + refs := make([]corev1.ObjectReference, 0, len(rev.Spec.Environment.EnvironmentConfigs)) for i, src := range rev.Spec.Environment.EnvironmentConfigs { switch src.Type { case v1.EnvironmentSourceTypeReference: refs = append( - refs[:idx], + refs, s.buildEnvironmentConfigRefFromRef(src.Ref), ) - idx++ case v1.EnvironmentSourceTypeSelector: - ec, err := s.lookUpConfigs(ctx, cr, src.Selector.MatchLabels) if err != nil { return errors.Wrapf(err, errFmtReferenceEnvironmentConfig, i) @@ -101,8 +96,7 @@ func (s *APIEnvironmentSelector) SelectEnvironment(ctx context.Context, cr resou if err != nil { return errors.Wrapf(err, errFmtReferenceEnvironmentConfig, i) } - refs = append(refs[:idx], r...) - idx += len(r) + refs = append(refs, r...) default: return errors.Errorf(errFmtInvalidEnvironmentSourceType, string(src.Type)) } @@ -136,34 +130,35 @@ func (s *APIEnvironmentSelector) lookUpConfigs(ctx context.Context, cr resource. } func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(cl *v1alpha1.EnvironmentConfigList, selector *v1.EnvironmentSourceSelector) ([]corev1.ObjectReference, error) { - ec := make([]v1alpha1.EnvironmentConfig, 0) - switch { - case len(cl.Items) == 0: + if len(cl.Items) == 0 { return []corev1.ObjectReference{}, nil + } - case selector.Mode == v1.EnvironmentSourceSelectorSingleMode: - - if len(cl.Items) != 1 { - return []corev1.ObjectReference{}, errors.Errorf(errFoundMultipleInSingleMode, len(cl.Items)) + switch selector.Mode { + case v1.EnvironmentSourceSelectorSingleMode: + switch len(cl.Items) { + case 1: + ec = append(ec, cl.Items[0]) + default: + return nil, errors.Errorf(errFmtFoundMultipleInSingleMode, len(cl.Items)) } - ec = append(ec, cl.Items[0]) - - case selector.Mode == v1.EnvironmentSourceSelectorMultiMode: + case v1.EnvironmentSourceSelectorMultiMode: err := sortConfigs(cl.Items, selector.SortByFieldPath) if err != nil { - return []corev1.ObjectReference{}, err + return nil, err } - if selector.MaxMatch == nil { - ec = append(ec, cl.Items...) - } else { + if selector.MaxMatch != nil { ec = append(ec, cl.Items[:*selector.MaxMatch]...) + break } + ec = append(ec, cl.Items...) default: - return []corev1.ObjectReference{}, errors.Errorf(errUnknownSelectorMode, selector.Mode) + // should never happen + return nil, errors.Errorf(errFmtUnknownSelectorMode, selector.Mode) } envConfigs := make([]corev1.ObjectReference, len(ec)) @@ -178,64 +173,65 @@ func (s *APIEnvironmentSelector) buildEnvironmentConfigRefFromSelector(cl *v1alp return envConfigs, nil } -type sortPair struct { - ec v1alpha1.EnvironmentConfig - obj map[string]interface{} -} - -//nolint:gocyclo // tbd -func sortConfigs(ec []v1alpha1.EnvironmentConfig, f string) error { - - var err error - - p := make([]sortPair, len(ec)) +func sortConfigs(ec []v1alpha1.EnvironmentConfig, f string) error { //nolint:gocyclo // TODO(phisco): refactor + p := make([]struct { + ec v1alpha1.EnvironmentConfig + val any + }, len(ec)) + var valsKind reflect.Kind for i := 0; i < len(ec); i++ { m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ec[i]) if err != nil { return err } - p[i] = sortPair{ - ec: ec[i], - obj: m, - } - } - sort.Slice(p, func(i, j int) bool { + val, err := fieldpath.Pave(m).GetValue(f) if err != nil { - return false + return err } - v1, e := fieldpath.Pave(p[i].obj).GetValue(f) - if e != nil { - err = e - return false + + vt := reflect.TypeOf(val).Kind() + + // check only vt1 as vt1 == vt2 + switch vt { //nolint:exhaustive // we only support these types + case reflect.String, reflect.Int64, reflect.Float64: + // ok + default: + return errors.Errorf(errFmtSortUnknownType, val) } - v2, e := fieldpath.Pave(p[j].obj).GetValue(f) - if err != nil { - err = e - return false + + if i == 0 { + valsKind = vt + } else if vt != valsKind { + // compare with previous values' kind + return errors.Errorf(errFmtSortNotMatchingTypes, val, valsKind) } - vt1 := reflect.TypeOf(v1).Kind() - vt2 := reflect.TypeOf(v2).Kind() - switch { - case vt1 == reflect.Float64 && vt2 == reflect.Float64: - return v1.(float64) < v2.(float64) - case vt1 == reflect.Int64 && vt2 == reflect.Int64: - return v1.(int64) < v2.(int64) - case vt1 == reflect.String && vt2 == reflect.String: - return v1.(string) < v2.(string) - case vt1 != vt2: - err = errors.Errorf(errSortNotMatchingTypes, v1, v2) + p[i].ec = ec[i] + p[i].val = val + } + + var err error + sort.Slice(p, func(i, j int) bool { + vali, valj := p[i].val, p[j].val + switch valsKind { //nolint:exhaustive // we only support these types + case reflect.Float64: + return vali.(float64) < valj.(float64) + case reflect.Int64: + return vali.(int64) < valj.(int64) + case reflect.String: + return vali.(string) < valj.(string) default: - err = errors.Errorf(errSortUnknownType, v1) + // should never happen + err = errors.Errorf(errFmtSortUnknownType, valsKind) + return false } - return false }) - if err != nil { return err } + for i := 0; i < len(ec); i++ { ec[i] = p[i].ec } diff --git a/internal/controller/apiextensions/composite/environment/selector_test.go b/internal/controller/apiextensions/composite/environment/selector_test.go index f1b061a23..24cf4af65 100644 --- a/internal/controller/apiextensions/composite/environment/selector_test.go +++ b/internal/controller/apiextensions/composite/environment/selector_test.go @@ -19,6 +19,7 @@ import ( "context" "encoding/json" "fmt" + "reflect" "testing" "github.com/google/go-cmp/cmp" @@ -296,8 +297,7 @@ func TestSelect(t *testing.T) { { Type: v1.EnvironmentSourceTypeSelector, Selector: &v1.EnvironmentSourceSelector{ - Mode: v1.EnvironmentSourceSelectorSingleMode, - SortByFieldPath: "metadata.name", + Mode: v1.EnvironmentSourceSelectorSingleMode, MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, @@ -347,8 +347,7 @@ func TestSelect(t *testing.T) { { Type: v1.EnvironmentSourceTypeSelector, Selector: &v1.EnvironmentSourceSelector{ - Mode: v1.EnvironmentSourceSelectorSingleMode, - SortByFieldPath: "metadata.name", + Mode: v1.EnvironmentSourceSelectorSingleMode, MatchLabels: []v1.EnvironmentSourceSelectorLabelMatcher{ { Type: v1.EnvironmentSourceSelectorLabelMatcherTypeValue, @@ -365,7 +364,7 @@ func TestSelect(t *testing.T) { }, want: want{ cr: composite(), - err: errors.Wrap(fmt.Errorf("only 1 EnvironmentConfig can be selected in Single mode, found: 2"), "failed to build reference at index 0"), + err: errors.Wrap(fmt.Errorf(errFmtFoundMultipleInSingleMode, 2), "failed to build reference at index 0"), }, }, "RefsInOrder": { @@ -941,7 +940,7 @@ func TestSelect(t *testing.T) { cr: composite( withEnvironmentRefs(), ), - err: errors.Wrap(fmt.Errorf("not matching types: int64 : float64"), "failed to build reference at index 0"), + err: errors.Wrap(fmt.Errorf(errFmtSortNotMatchingTypes, int64(1), reflect.Float64), "failed to build reference at index 0"), }, }, "ErrSelectOnUnexpectedType": { From abecd463d589c7a196da7c259a62065081d536f0 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Thu, 13 Jul 2023 12:26:02 +0200 Subject: [PATCH 064/148] fix xfn e2e tests on osx when docker engine runs inside a VM, it is not possible to reach k8s nodes from the hosts. In order to make possible to copy images from host to the container registry running inside kind cluster, we need to add extra port mappings to the kind configuration as suggested in https://kind.sigs.k8s.io/docs/user/configuration/#extra-port-mappings We start kind with such configuration and later on when image copying is needed, we detect if our cluster is kind and use proper address to reach the registry. Otherwise, we fall back on detecting node address. Signed-off-by: Predrag Knezevic --- test/e2e/main_test.go | 17 ++++++++++--- test/e2e/testdata/kindConfig.yaml | 8 ++++++ test/e2e/xfn_test.go | 41 ++++++++++++++++++------------- 3 files changed, 45 insertions(+), 21 deletions(-) create mode 100644 test/e2e/testdata/kindConfig.yaml diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 6cb8a456a..03a6ffec0 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -19,6 +19,7 @@ package e2e import ( "flag" "os" + "path/filepath" "strings" "testing" @@ -116,8 +117,11 @@ func HelmOptions(extra ...helm.Option) []helm.Option { return append(o, extra...) } -// The test environment, shared by all E2E test functions. -var environment env.Environment +var ( + // The test environment, shared by all E2E test functions. + environment env.Environment + clusterName string +) func TestMain(m *testing.M) { // TODO(negz): Global loggers are dumb and klog is dumb. Remove this when @@ -136,7 +140,7 @@ func TestMain(m *testing.M) { cfg, _ := envconf.NewFromFlags() - clusterName := envconf.RandomName("crossplane-e2e", 32) + clusterName = envconf.RandomName("crossplane-e2e", 32) if *kindClusterName != "" { clusterName = *kindClusterName } @@ -144,8 +148,13 @@ func TestMain(m *testing.M) { // we want to create the cluster if it doesn't exist, but only if we're isKindCluster := *create || *kindClusterName != "" if isKindCluster { + kindCfg, err := filepath.Abs(filepath.Join("test", "e2e", "testdata", "kindConfig.yaml")) + if err != nil { + log.Log.Error(err, "error getting kind config file") + os.Exit(1) + } setup = []env.Func{ - envfuncs.CreateKindCluster(clusterName), + envfuncs.CreateKindClusterWithConfig(clusterName, "kindest/node:v1.27.3", kindCfg), } } else { cfg.WithKubeconfigFile(conf.ResolveKubeConfigFile()) diff --git a/test/e2e/testdata/kindConfig.yaml b/test/e2e/testdata/kindConfig.yaml new file mode 100644 index 000000000..90ee5b5e5 --- /dev/null +++ b/test/e2e/testdata/kindConfig.yaml @@ -0,0 +1,8 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane + extraPortMappings: + # expose NodePort 32000 to the host + - containerPort: 32000 + hostPort: 3000 \ No newline at end of file diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index b847a35c5..368e955df 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -106,24 +106,31 @@ func TestXfnRunnerImagePull(t *testing.T) { ))), ). WithSetup("CopyFnImageToRegistry", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - nodes := &corev1.NodeList{} - if err := config.Client().Resources().List(ctx, nodes); err != nil { - t.Fatal("cannot list nodes", err) - } - if len(nodes.Items) == 0 { - t.Fatalf("no nodes in the cluster") - } - var addr string - for _, a := range nodes.Items[0].Status.Addresses { - if a.Type == corev1.NodeInternalIP { - addr = a.Address - break + var reg string + _, found := envfuncs.GetKindClusterFromContext(ctx, clusterName) + if found { + reg = "localhost:3000" + t.Logf("Running tests against kind cluster, container registry accessible from host via %s", reg) + } else { + nodes := &corev1.NodeList{} + if err := config.Client().Resources().List(ctx, nodes); err != nil { + t.Fatal("cannot list nodes", err) } + if len(nodes.Items) == 0 { + t.Fatalf("no nodes in the cluster") + } + var addr string + for _, a := range nodes.Items[0].Status.Addresses { + if a.Type == corev1.NodeInternalIP { + addr = a.Address + break + } + } + if addr == "" { + t.Fatalf("no nodes with private address") + } + reg = fmt.Sprintf("%s:32000", addr) } - if addr == "" { - t.Fatalf("no nodes with private address") - } - srcRef, err := name.ParseReference("crossplane-e2e/fn-labelizer:latest") if err != nil { t.Fatal(err) @@ -133,7 +140,7 @@ func TestXfnRunnerImagePull(t *testing.T) { t.Fatal(err) } err = wait.For(func() (done bool, err error) { - err = crane.Push(src, fmt.Sprintf("%s:32000/fn-labelizer:latest", addr), crane.Insecure) + err = crane.Push(src, fmt.Sprintf("%s/fn-labelizer:latest", reg), crane.Insecure) if err != nil { return false, nil //nolint:nilerr // we want to retry and to throw error } From 699f0578864f76262ff9156cae8343aa9519fed9 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Thu, 13 Jul 2023 17:10:40 +0200 Subject: [PATCH 065/148] use default kind image Co-authored-by: Philippe Scorsolini Signed-off-by: Predrag Knezevic --- test/e2e/main_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 03a6ffec0..155e419f1 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -154,7 +154,7 @@ func TestMain(m *testing.M) { os.Exit(1) } setup = []env.Func{ - envfuncs.CreateKindClusterWithConfig(clusterName, "kindest/node:v1.27.3", kindCfg), + envfuncs.CreateKindClusterWithConfig(clusterName, "\"\"", kindCfg), } } else { cfg.WithKubeconfigFile(conf.ResolveKubeConfigFile()) From 284d6f79ad75db6ee81a69d4986630b6fd7f5fc0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:09:00 +0000 Subject: [PATCH 066/148] Update dependency helm/helm to v3.12.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd63433a8..6c135121a 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ GOLANGCILINT_VERSION = 1.53.3 # Setup Kubernetes tools USE_HELM3 = true -HELM3_VERSION = v3.12.1 +HELM3_VERSION = v3.12.2 KIND_VERSION = v0.20.0 -include build/makelib/k8s_tools.mk From 071e2caaaef8d99a914d3136e5ca8d01cee61240 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 20:45:55 +0000 Subject: [PATCH 067/148] Update module github.com/bufbuild/buf to v1.24.0 --- go.mod | 28 ++++++++++++++-------------- go.sum | 56 ++++++++++++++++++++++++++++---------------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index ea2f3bb28..ecb39a011 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 - github.com/bufbuild/buf v1.23.1 + github.com/bufbuild/buf v1.24.0 github.com/crossplane/crossplane-runtime v0.20.0-rc.0.0.20230622044456-2dfb8bc6bfbc github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 @@ -67,8 +67,8 @@ require ( github.com/aws/smithy-go v1.13.5 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20230510185313-f5e39e5f34c7 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bufbuild/connect-go v1.8.0 // indirect - github.com/bufbuild/connect-opentelemetry-go v0.3.0 // indirect + github.com/bufbuild/connect-go v1.9.0 // indirect + github.com/bufbuild/connect-opentelemetry-go v0.4.0 // indirect github.com/bufbuild/protocompile v0.5.1 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -78,9 +78,9 @@ require ( github.com/dave/jennifer v1.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect - github.com/docker/cli v24.0.2+incompatible // indirect + github.com/docker/cli v24.0.4+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.2+incompatible // indirect + github.com/docker/docker v24.0.4+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -107,7 +107,7 @@ require ( github.com/google/gnostic v0.6.9 // indirect github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230516205744-dbecb1de8cfa // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect + github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.0.0 // indirect @@ -125,7 +125,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -140,7 +140,7 @@ require ( github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc3 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/profile v1.7.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect @@ -162,14 +162,14 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.10.0 // indirect - golang.org/x/mod v0.11.0 // indirect - golang.org/x/net v0.11.0 // indirect; indirect // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect; indirect // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/term v0.9.0 // indirect - golang.org/x/text v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.10.0 // indirect + golang.org/x/tools v0.11.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect diff --git a/go.sum b/go.sum index 47a6cd29a..48386f072 100644 --- a/go.sum +++ b/go.sum @@ -121,12 +121,12 @@ github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bufbuild/buf v1.23.1 h1:BeMkA3+e9XTFEZPDlAI7cydFKlq24wwYiOHp8CvsRzc= -github.com/bufbuild/buf v1.23.1/go.mod h1:ERFRzJiIjAOzUSJ3vz1zoI7XfxlBnCwZEyL+NJm4pko= -github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc= -github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= -github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk= -github.com/bufbuild/connect-opentelemetry-go v0.3.0/go.mod h1:r1ppyTtu1EWeRodk4Q/JbyQhIWtO7eR3GoRDzjeEcNU= +github.com/bufbuild/buf v1.24.0 h1:36rVJMJX7BI9Z6nUPpirF+TUO9tVZ45u5VAfj5E7Bgw= +github.com/bufbuild/buf v1.24.0/go.mod h1:cacBvncWbYnUcNX580lqllR3qlEetMX/KVm27pUc4Kc= +github.com/bufbuild/connect-go v1.9.0 h1:JIgAeNuFpo+SUPfU19Yt5TcWlznsN5Bv10/gI/6Pjoc= +github.com/bufbuild/connect-go v1.9.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= +github.com/bufbuild/connect-opentelemetry-go v0.4.0 h1:6JAn10SNqlQ/URhvRNGrIlczKw1wEXknBUUtmWqOiak= +github.com/bufbuild/connect-opentelemetry-go v0.4.0/go.mod h1:nwPXYoDOoc2DGyKE/6pT1Q9MPSi2Et2e6BieMD0l6WU= github.com/bufbuild/protocompile v0.5.1 h1:mixz5lJX4Hiz4FpqFREJHIXLfaLBntfaJv1h+/jS+Qg= github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= @@ -171,12 +171,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/docker/cli v24.0.2+incompatible h1:QdqR7znue1mtkXIJ+ruQMGQhpw2JzMJLRXp6zpzF6tM= -github.com/docker/cli v24.0.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v24.0.4+incompatible h1:Y3bYF9ekNTm2VFz5U/0BlMdJy73D+Y1iAAZ8l63Ydzw= +github.com/docker/cli v24.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.2+incompatible h1:eATx+oLz9WdNVkQrr0qjQ8HvRJ4bOOxfzEo8R+dA3cg= -github.com/docker/docker v24.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= +github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -313,8 +313,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= +github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -379,8 +379,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -433,8 +433,8 @@ github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= -github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runtime-spec v1.1.0-rc.3.0.20230610073135-48415de180cf h1:AGnwZS8lmjGxN2/XlzORiYESAk7HOlE3XI37uhIP9Vw= github.com/opencontainers/runtime-spec v1.1.0-rc.3.0.20230610073135-48415de180cf/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -546,8 +546,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -585,8 +585,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -625,8 +625,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -713,8 +713,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -726,8 +726,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -787,8 +787,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= -golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 1e10304f5212dc810296be7b82d1f28f775946e3 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Fri, 7 Jul 2023 15:41:01 -0700 Subject: [PATCH 068/148] Design for for beta Functions This commit introduces an updated design for Composition Functions. Under this design Functions are long-running processes, like Providers. Crossplane makes RunFunctionRequest RPCs to a Function using gRPC. This updated design also sketches out an improved Function development experience, as well as a few hypothetical 'generic' Functions. A generic Function is a Function that works with any XR. Generic Functions extend Crossplane with new ways to express Composition logic without actually needing to develop a Function of your own. Signed-off-by: Nic Cope --- .../containerized-functions.png | Bin 0 -> 449354 bytes .../functions.png | Bin 0 -> 425437 bytes .../design-doc-composition-functions.md | 778 ++++++++++ design/design-doc-composition-functions.md | 1360 ++++++++++------- 4 files changed, 1574 insertions(+), 564 deletions(-) create mode 100644 design/assets/design-doc-composition-functions/containerized-functions.png create mode 100644 design/assets/design-doc-composition-functions/functions.png create mode 100644 design/defunct/design-doc-composition-functions.md diff --git a/design/assets/design-doc-composition-functions/containerized-functions.png b/design/assets/design-doc-composition-functions/containerized-functions.png new file mode 100644 index 0000000000000000000000000000000000000000..819b348f6a25346f53cc28e2b2ad6933e39d3646 GIT binary patch literal 449354 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�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%0ALlIeA^swKWX~#2lLXHQP@P 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 n4;*9uZ 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 literal 0 HcmV?d00001 diff --git a/design/assets/design-doc-composition-functions/functions.png b/design/assets/design-doc-composition-functions/functions.png new file mode 100644 index 0000000000000000000000000000000000000000..c4f1bc4aa203753c3bdb8f313b159ce5fa44f5d8 GIT binary patch literal 425437 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

HW6a4WJyQb(%7{5*1{aa?7 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 x=*;kWsY%Mz}HlhB2 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

{7Oz& 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

{g?vZX4jL8R)m9B!+RFZt%JUNL3rWXF(S{0&I|g z%Vkvr*a4uwx6n7UQAi*<{i2ZkibQq}oy)fia$LVCY$i5RC;IRE%K|u)G_qtW^ zy$mA*$Fd7}_a*Eq08jUzRUOh0P$VF$ zi!LvKczJ|_K^&B(N}8PQK@ZIH6?i)WZdI#zf(n8ncXY2%#rKE=Wl89{9rU#^4K5%< zUM|xEve}v@z@v8b&a$2iyUJDC`wⅆ{I1bpE=q~?4(3~Y(?3iw4F3T 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�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 Folks accustomed to Terraform might think of a Composition as a Terraform +> module; the HCL code that describes how to take input variables and use them +> to create resources in some cloud API. Folks accustomed to Helm might think of +> a Composition as a Helm chart’s templates; the moustache templated YAML files +> that describe how to take Helm chart values and render Kubernetes resources. + +A Crossplane `Composition` consists of an array of one or more 'base' +resources. Each of these resources can be 'patched' with values derived from the +XR. The functionality enabled by a `Composition` is intentionally limited - for +example there is no support for conditionals (e.g. only create this resource if +the following conditions are met) or iteration (e.g. create N of the following +resource, where N is derived from an XR field). + +Below is an example `Composition`: + +```yaml +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: database.example.org/v1alpha1 + kind: AcmeCoDatabase + resources: + - name: cloudsqlinstance + base: + apiVersion: database.gcp.crossplane.io/v1beta1 + kind: CloudSQLInstance + spec: + forProvider: + databaseVersion: POSTGRES_9_6 + region: us-central1 + settings: + tier: db-custom-1-3840 + dataDiskType: PD_SSD + patches: + - type: FromCompositeFieldPath + fromFieldPath: spec.parameters.storageGB + toFieldPath: spec.forProvider.settings.dataDiskSizeGb +``` + +The goals of the Crossplane maintainers in designing Composition were to: + +* Empower platform teams to provide a platform of useful, opinionated + abstractions. +* Enable platform teams to define abstractions that may be portable across + different infrastructure providers and application runtimes. +* Enable platform teams to share and reuse the abstractions they define. +* Leverage the Kubernetes Resource Model (KRM) to model applications, + infrastructure, and the product of the two in a predictable, safe, and + declarative fashion using low or no code. +* Avoid imposing unnecessary opinions, assumptions, or constraints around how + applications and infrastructure should function. + +The design document for Composition [captures these goals][composition-design] +using somewhat dated parlance. + +Our approach to achieving our goals was heavily informed by Brian Grant’s +[Declarative application management in Kubernetes][declarative-app-management]. +Brian’s document is an excellent summary of the gotchas and pitfalls faced by +those attempting to design new configuration management tools, informed by his +experiences designing Kubernetes, its precursor Borg, and many generations of +configuration languages at Google, including [BCL/GCL][bcl]. In particular, we +wanted to: + +* Avoid organically growing a new DSL. These languages tend to devolve to + incoherency as stakeholders push to “bolt on” new functionality to solve + pressing problems at the expense of measured design. Terraform’s DSL + unintuitively [supporting the count argument in some places but not + others][terraform-count] is a great example of this. Inventing a new DSL also + comes with the cost of inventing new tooling to test, lint, generate, etc, + your DSL. +* Stick to configuration that could be modeled as a REST API. Modeling + Composition logic as a schemafied API resource makes it possible for + Crossplane to validate that logic and provide feedback to the platform team at + configuration time. It also greatly increases interoperability thanks to broad + support across tools and languages for interacting with REST APIs. + +It was also important to avoid the “worst of both worlds” - i.e. growing a fully +featured ([Turing-complete][turing-complete]) DSL modeled as a REST API. To this +end we omitted common language features such as conditionals and iteration. Our +rationale being that these features were better deferred to a General Purpose +Programming Language (GPL) designed by language experts, and with extensive +existing tooling. + +Since its inception the Crossplane maintainers’ vision has been that there +should essentially be two variants of Composition: + +* For simple cases, use contemporary "Patch and Transform" (P&T) Composition. +* For advanced cases, bring your tool or programming language of choice. + +In this context a “simple case” might involve composing fewer than ten resources +without the need for logic such as conditionals and iteration. Note that the +Composition logic, whether P&T or deferred to a tool or programming language, is +always behind the API line (behind an XR). This means the distinction is only +important to the people authoring the Compositions, never to the people +consuming them. + +Offering two variants of Composition allows Crossplane users to pick the one +that is best aligned with their situation, preferences, and experience level. +For simple cases you don’t need to learn a new programming language or tool, and +there are no external dependencies - just write familiar, Kubernetes-style YAML. +For advanced cases leverage proven tools and languages with existing ecosystems +and documentation. Either way, Crossplane has no religion - if you prefer not to +“write YAML”, pick another tool and vice versa. + +## Goals + +The proposal put forward by this document should: + +* Let folks use their composition tool and/or programming language of choice. +* Support 'advanced' composition logic such as loops and conditionals. +* Balance safety (e.g. sandboxing) with speed and simplicity. +* Be possible to introduce behind a feature flag that is off by default. + +While not an explicit goal, it would also be ideal if the solution put forth by +this document could serve as a test bed for new features in the contemporary +'resources array' based form of Composition. + +The user experience around authoring and maintaining Composition Functions is +out of scope for this proposal, which focuses only on adding foundational +support for the feature to Crossplane. + +## Proposal + +### Overview + +This document proposes that a new `functions` array be added to the existing +`Composition` type. This array of functions would be called either instead of or +in addition to the existing `resources` array in order to determine how an XR +should be composed. The array of functions acts as a pipeline; the output of +each function is passed as the input to the next. The output of the final +function tells Crossplane what must be done to reconcile the XR. + +```yaml +apiVersion: apiextensions.crossplane.io/v2alpha1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: database.example.org/v1alpha1 + kind: XPostgreSQLInstance + functions: + - name: my-cool-function + type: Container + container: + image: xkpg.io/my-cool-function:0.1.0 +``` + +Under this proposal each function is the entrypoint of an OCI image, though the +API is designed to support different function implementations (such as webhooks) +in the future. The updated API would affect only the `Composition` type - no +changes would be required to the schema of `CompositeResourceDefinitions`, XRs, +etc. + +Notably the functions would not be responsible for interacting with the API +server to create, update, or delete composed resources. Instead, they instruct +Crossplane which resources should be created, updated, or deleted. + +Under the proposed design functions could also be used for purposes besides +rendering composed resources, for example validating the results of the +`resources` array or earlier functions in the `functions` array. Furthermore, a +function could also be used to implement 'side effects' such as triggering a +replication or backup. + +Below is a more detailed example of an entry in the `functions` array. + +```yaml +apiVersion: apiextensions.crossplane.io/v2alpha1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: database.example.org/v1alpha1 + kind: XPostgreSQLInstance + functions: + - name: my-cool-function + type: Container + # Configuration specific to `type: Container` functions. + container: + # The OCI image to pull and run. + image: xkpg.io/my-cool-function:0.1.0 + # Whether to pull the function Never, Always, or IfNotPresent. + imagePullPolicy: IfNotPresent + # Secrets used to pull from a private registry. + imagePullSecrets: + - namespace: crossplane-system + name: my-xpkg-io-creds + # Note that only resource limits are supported - not requests. + # The function will be run with the specified resource limits. + resources: + limits: + memory: 64Mi + cpu: 250m + # Defaults to 'Isolated' - i.e an isolated network namespace. + network: Accessible + # How long the function may run before it's killed. Defaults to 10s. + timeout: 30s + # Containers are run by an external process listening at the supplied + # endpoint. Specifying an endpoint is optional; the endpoint defaults to + # the below value. + runner: + endpoint: unix:///@crossplane/fn/default.sock + # An x-kubernetes-embedded-resource RawExtension (i.e. an unschemafied + # Kubernetes resource). Passed to the function as the config block of its + # FunctionIO. + config: + apiVersion: database.example.org/v1alpha1 + kind: Config + metadata: + name: cloudsql + spec: + version: POSTGRES_9_6 +``` + +### Function API + +This document proposes that each function uses a `FunctionIO` type as its input +and output. In the case of `Container` functions this would correspond to stdin +and stdout. Crossplane would be responsible for reading stdout from the final +function and applying its changes to the relevant XR and composed resources. + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +config: + apiVersion: database.example.org/v1alpha1 + kind: Config + metadata: + name: cloudsql + spec: + version: POSTGRES_9_6 +observed: + composite: + resource: + apiVersion: database.example.org/v1alpha1 + kind: XPostgreSQLInstance + metadata: + name: my-db + spec: + parameters: + storageGB: 20 + compositionSelector: + matchLabels: + provider: gcp + status: + conditions: + - type: Ready + status: True + connectionDetails: + - name: uri + value: postgresql://db.example.org:5432 +``` + +A `FunctionIO` resource consists of the following top-level fields: + +* The `apiVersion` and `kind` (required). +* A `config` object (optional). This is a [Kubernetes resource][rawextension] + with an arbitrary schema that may be used to provide additional configuration + to a function. For example a `render-helm-chart` function might use its + `config` to specify which Helm chart to render. Functions need not return + their `config`, and any mutations will be ignored. +* An `observed` object (required). This reflects the observed state of the XR, + any existing composed resources, and their connection details. Functions must + return the `observed` object unmodified. +* A `desired` object (optional). This reflects the accumulated desired state of + the XR and any composed resources. Functions may mutate the `desired` object. +* A `results` array (optional). Used to communicate information about the result + of a function, including warnings and errors. Functions may mutate the + `results` object. + +Each function takes its `config` (if any), `observed` state, and any previously +accumulated `desired` state as input, and optionally mutates the `desired` +state. This allows the output of one function to be the input to the next. + +The `observed` object consists of: + +* `observed.composite.resource`. The observed XR. +* `observed.composite.connectionDetails`: The observed XR connection details. +* `observed.resources[N].name`: The name of an observed composed resource. +* `observed.resources[N].resource`: An observed composed resource. +* `observed.resources[N].connectionDetails`: An observed composed resource's + current connection details. + +If an observed composed resource appears in the Composition's `spec.resources` +array their `name` fields will match. Note that the `name` field is distinct +from a composed resource's `metadata.name` - it is used to identify the resource +within a Composition and/or its function pipeline. + +The `desired` object consists of: + +* `desired.composite.resource`. The desired XR. +* `desired.composite.resource.connectionDetails`. Desired XR connection details. +* `desired.resources[N].name`. The name of a desired composed resource. +* `desired.resources[N].resource`. A desired composed resource. +* `desired.resources[N].connectionDetails`. A desired composed resource's + connection details. +* `desired.resources[N].readinessChecks`. A desired composed resource's + readiness checks. + +Note that the `desired.resources` array of the `FunctionIO` type is very +similar to the `spec.resources` array of the `Composition` type. In comparison: + +* `name` works the same across both types, but is required by `FunctionIO`. +* `connectionDetails` and `readinessChecks` work the same across both types. +* `FunctionIO` does not support `base` and `patches`. Instead, a function should + configure the `resource` field accordingly. + +The `desired` state is _accumulated_ across the Composition and all of its +functions. This means the first function may be passed desired state as +specified by the `spec.resources` array of a Composite, if any, and each +function must include the accumulated desired state in its output. Desired state +is treated as an overlay on observed state, so a function pipeline need not +specify the desired state of the XR (for example) unless a function wishes to +mutate it. + +A full `FunctionIO` specification will accompany the implementation. Some +example scenarios are illustrated below. + +A function that wanted to create (compose) a `CloudSQLInstance` would do so by +returning the following `FunctionIO`: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: {} # Omitted for brevity. +desired: + resources: + - name: cloudsqlinstance + resource: + apiVersion: database.gcp.crossplane.io/v1beta1 + kind: CloudSQLInstance + spec: + forProvider: + databaseVersion: POSTGRES_9_6 + region: us-central1 + settings: + tier: db-custom-1-3840 + dataDiskType: PD_SSD + dataDiskSizeGb: 20 + writeConnectionSecretToRef: + namespace: crossplane-system + name: cloudsqlpostgresql-conn + connectionDetails: + - name: hostname + fromConnectionSecretKey: hostname + readinessChecks: + - type: None +``` + +A function that wanted to set only an XR connection detail could return: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: {} # Omitted for brevity. +desired: + composite: + connectionDetails: + - type: FromValue + name: username + value: admin +``` + +A function wishing to delete a composed resource may do so by setting its +`resource` to null, for example: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: {} # Omitted for brevity. +desired: + resources: + - name: cloudsqlinstance + resource: null +``` + +A function that could not complete successfully could do so by returning the +following `FunctionIO`: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +config: + apiVersion: database.example.org/v1alpha1 + kind: Config + metadata: + name: cloudsql + spec: + version: POSTGRES_9_6 +observed: {} # Omitted for brevity. +results: +- severity: Error + message: "Could not render Database.postgresql.crossplane.io/v1beta1` +``` + +### Running Container Function Pipelines + +While Crossplane typically runs in a Kubernetes cluster - a cluster designed to +run containers - running an ordered _pipeline_ of short-lived containers via +Kubernetes is much less straightforward than you might expect. Refer to +[Alternatives Considered](#alternatives-considered) for details. + +In order to provide flexibility and choice of tradeoffs in running containers +(e.g. speed, scalability, security) this document proposes Crossplane defer +containerized functions to an external runner. Communication with the runner +would occur via a gRPC API, with the runner expected to be listening at the +`endpoint` specified via the function's `runner` configuration block. This +endpoint would default to `unix:///@crossplane/fn/default.sock` - an abstract +[Unix domain socket][unix-domain-sockets]. + +Communication between Crossplane and a containerized function runner would use +the following API: + +```protobuf +syntax = "proto3"; + +// This service defines the APIs for a containerized function runner. +service ContainerizedFunctionRunner { + rpc RunFunction(RunFunctionRequest) returns (RunFunctionResponse) {} +} + +// Corresponds to Kubernetes' image pull policy. +enum ImagePullPolicy { + IF_NOT_PRESENT = 0; + ALWAYS = 1; + NEVER = 2; +} + +// Corresponds to go-containerregistry's AuthConfig type. +// https://pkg.go.dev/github.com/google/go-containerregistry@v0.11.0/pkg/authn#AuthConfig +message ImagePullAuth { + string username = 1; + string password = 2; + string auth = 3; + string identity_token = 4; + string registry_token = 5; +} + +message ImagePullConfig { + ImagePullPolicy pull_policy = 1; + ImagePullAuth auth = 2; +} + +// Containers are run without network access (in an isolated network namespace) +// by default. +enum NetworkPolicy = { + ISOLATED = 0; + ACCESSIBLE = 1; +} + +// Only resource limits are supported. Resource requests could be added in +// future if a runner supported them (e.g. by running containers on Kubernetes). +message Resources { + ResourceLimits limits = 1; +} + +message ResourceLimits { + string memory = 1; + string cpu = 2; +} + +message RunFunctionConfig { + Resources resources = 1; + NetworkPolicy network = 2; + Duration timeout = 3; +} + +// The input FunctionIO is supplied as opaque bytes. +message RunFunctionRequest { + string image = 1; + bytes input = 2; + ImagePullConfig = 3; + RunFunctionConfig = 4; +} + +// The output FunctionIO is supplied as opaque bytes. Errors encountered while +// running a function (as opposed to errors returned _by_ a function) will be +// encapsulated as gRPC errors. +message RunFunctionResponse { + bytes output = 1; +} +``` + +### The Default Function Runner + +This document proposes that Crossplane include a default function runner. This +runner would be implemented as a sidecar to the core Crossplane container that +runs functions inside itself. + +The primary advantages of this approach are speed and control. There's no need +to wait for another system (for example the Kubernetes control plane) to +schedule each container, and the runner can easily pass stdout from one +container to another's stdin. Speed of function runs is of particular importance +given that each XR typically reconciles (i.e. invokes its function pipeline) +once every 60 seconds. + +The disadvantages of running the pipeline inside a sidecar container are scale +and reinvention of the wheel. The resources available to the sidecar container +will bound how many functions it can run at any one time, and it will need to +handle features that the Kubelet already offers such as pull secrets, caching +etc. + +[Rootless containers][rootless] appear to be the most promising way to run +functions as containers inside a container: + +> Rootless containers uses `user_namespaces(7)` (UserNS) for emulating fake +> privileges that are enough to create containers. The pseudo-root user gains +> capabilities such as `CAP_SYS_ADMIN` and `CAP_NET_ADMIN` inside UserNS to +> perform fake-privileged operations such as creating mount namespaces, network +> namespaces, and creating TAP devices. + +Using user namespaces allows the runner to use the other kinds of namespaces +listed above to ensure an extra layer of isolation for the functions it runs. +For example a network namespace could be configured to prevent a function having +network access. + +User namespaces are well supported by modern Linux Kernels, having been +introduced in Linux 3.8. Many OCI runtimes (including `runc`, `crun`, and +`runsc`) support rootless mode. `crun` appears to be the most promising choice +because: + +* It is more self-contained than `runc` (the reference and most commonly used + OCI runtime), which relies on setuid binaries to setup user namespaces. +* `runsc` (aka gVisor) uses extra defense in depth features which are not + allowed inside most containers due to their seccomp policies. + +Of course, "a container" is in fact many technologies working together and some +parts of rootless containers are less well supported than others; for example +cgroups v2 is required in order to limit resources like CPU and memory available +to a particular function. cgroups v2 has been available in Linux since 4.15, but +was not enabled by many distributions until 2021. In practice this means +Crossplane users must use a [sufficiently modern][cgroups-v2-distros] +distribution on their Kubernetes nodes in order to constrain the resources of a +Composition function. + +Similarly, [overlayfs] was not allowed inside user namespaces until Linux 5.11. +Overlayfs is typically used to create a root filesystem for a container that is +backed by a read-write 'upper' directory overlaid on a read-only 'lower' +directory. This allows the root OCI image filesystem to persist as a cache of +sorts, while changes made during the lifetime of a container can be easily +discarded. It's possible to replicate these benefits (at the expense of disk +usage and start-up time) by falling back to making a throwaway copy of the root +filesystem for each container run where overlayfs is not available. + +Under the approach proposed by this document each function run would involve the +following steps: + +1. Use [go-containerregistry] to pull the function's OCI image. +1. Extract (untar) the OCI image's flattened filesystem to disk. +1. Create a filesystem for the container - either an overlay or a copy of the + filesystem extracted in step 2. +1. Derive an [OCI runtime configuration][oci-rt-cfg] from the + [OCI image configuration][oci-img-cfg] supplied by go-containerregistry. +1. Execute `crun run` to invoke the function in a rootless container. + +Executing `crun` directly as opposed to using a higher level tool like `docker` +or `podman` allows the default function runner to avoid new dependencies apart +from a single static binary (i.e. `crun`). It keeps most functionality (pulling +images etc) inside the runner's codebase, delegating only container creation to +an external tool. Composition Functions are always short-lived and should always +have their stdin and stdout attached to the runner, so wrappers like +`containerd-shim` or `conmon` should not be required. The short-lived, "one +shot" nature of Composition Functions means it should also be acceptable to +`crun run` the container rather than using `crun create`, `crun start`, etc. + +At the time of writing rootless containers appear to be supported by Kubernetes, +including Amazon's Elastic Kubernetes Service (EKS) and Google Kubernetes Engine +(GKE). + +Testing using GKE 1.21.10-gke.2000 with Container Optimized OS (with containerd) +cos-89-16108-604-19 nodes (Kernel COS-5.4.170) found that it was possible to run +`unshare -rUm` (i.e. to create a new user and mount namespace) inside an Alpine +Linux container as long as AppArmor was disabled by applying the annotation +`container.apparmor.security.beta.kubernetes.io/${CONTAINER_NAME}=unconfined`. +It's possible to create user namespaces with AppArmor enabled, but not to create +mount namespaces with different mount propagation from their parent. + +It is not possible to use rootless containers with gVisor enabled, as gVisor +does not yet [support mount namespaces][gvisor-mountns]. This means that it is +not possible to use rootless containers with GKE Autopilot, which requires that +gVisor be used. + +Testing using EKS v1.21.5-eks-9017834 with Amazon Linux 2 nodes (Kernel +5.4.188-104.359.amzn2.x86_64) found that it was possible to run `unshare -rUm` +inside an Alpine Linux container 'out of the box'. + +The `unshare` syscall used to create containers is rejected by the default +Docker and containerd seccomp profiles. seccomp is disabled ("Unconstrained") by +default in Kubernetes, but that will soon change per [this KEP][kep-seccomp] +which proposes that Kubernetes use the seccomp profiles of its container engine +(i.e. containerd) by default. Once this happens Crossplane will either need to +run with the "Unconstrained" seccomp profile, or a variant of the default +containerd seccomp profile that allows a few extra syscalls (i.e. at least +`unshare` and `mount`). This can be done by setting a Pod's +`spec.securityContext.seccompProfile.type` field to `Unconstrained`. + +### Packaging Containerized Functions + +This document proposes that containerized functions support Crossplane [package +metadata][package-meta] in the form of a `package.yaml` file at the root of the +flattened filesystem and/or the OCI layer annotated as `io.crossplane.xpkg: +base` per the [xpkg spec][xpkg-spec]. This `package.yaml` file would contain a +custom-resource-like YAML document of type `Function.meta.pkg.crossplane.io`. + +Unlike `Configuration` and `Provider` packages, `Function` packages would not +actually be processed by the Crossplane package manager but rather by the +Composition (`apiextensions`) machinery. In practice Crossplane would be +ignorant of the `package.yaml` file; it would exist purely as a way to attach +"package-like" metadata to containerized Crossplane functions. Therefore, unlike +the existing package types the `package.yaml` would contain no `spec` section. + +An example `package.yaml` might look like: + +```yaml +# Required. Must be as below. +apiVersion: meta.pkg.crossplane.io/v1alpha1 +# Required. Must be as below. +kind: Function +# Required. +metadata: + # Required. Must comply with Kubernetes API conventions. + name: function-example + # Optional. Must comply with Kubernetes API conventions. + annotations: + meta.crossplane.io/source: https://github.com/negz/example-fn + meta.crossplane.io/description: An example function +``` + +## Alternatives Considered + +Most of the alternatives considered in this design could also be thought of as +future considerations. In most cases these alternatives don't make sense at the +present time but likely will in the future. + +### Using Webhooks to Run Functions + +Crossplane could invoke functions by calling a webhook rather than running an +OCI container. In this model function input and output would still take the form +of a `FunctionIO`, but would be HTTP request and response bodies rather than a +container's stdin and stdout. + +The primary detractor of this approach is the burden it puts on function authors +and Crossplane operators. Rather than simply publishing an OCI image the author +and/or Crossplane operator must deploy and operate a web server, ensuring secure +communication between Crossplane and the webhook endpoint. + +Support for `type: Webhook` functions will likely be added shortly after initial +support for `type: Container` functions is released. + +### Using chroots to Run Functions + +Crossplane could invoke functions packaged as OCI images by unarchiving them and +then running them inside a simple `chroot`. This offers more compatibility than +rootless containers at the expense of isolation - it's not possible to constrain +a chrooted function's compute resources, network access, etc. `type: Chroot` +functions would use the same artifacts as `type: Container` functions but invoke +them differently. + +Support for `type: Chroot` functions could be added shortly after initial +support for `type: Container` functions are released if `type: Container` proves +to be insufficiently compatible (e.g. for clusters running gVisor, or that +require seccomp be enabled). + +### Using Kubernetes to Run Containerized Functions + +Asking Kubernetes to run a container pipeline is less straightforward than you +might think. Crossplane could schedule a `Pod` for each XR reconcile, or create +a `CronJob` to do so regularly. Another option could be to connect directly to a +Kubelet. This approach would enjoy all the advantages of the existing Kubelet +machinery (pull secrets, caching, etc) but incurs overhead in other areas, for +example: + +* Every reconcile requires a pod to be scheduled, which may potentially block on + node scale-up, etc. +* stdin and stdout must be streamed via the API server, for example by using the + [`/attach` subresource][attach]. +* Running containers in order requires either (ab)using init containers or + injecting a middleware binary that blocks container starts to ensure they run + in order (similar to Argo Workflow's '[emissary]' executor): + +> The emissary works by replacing the container's command with its own command. +> This allows that command to capture stdout, the exit code, and easily +> terminate your process. The emissary can also delay the start of your process. + +You can see some of the many options Argo Workflows explored to address these +issues before landing on `emissary` in their list of +[deprecated executors][argo-deprecated-executors]. + +### Using KRM Function Spec Compliant Functions + +While the design proposed by this document is heavily inspired by KRM Functions, +the [KRM function specification][krm-fn-spec] as it currently exists is not an +ideal fit. This is because: + +1. It is built around the needs of CLI tooling - including several references to + (client-side) 'files' that don't exist in the Crossplane context. +1. Crossplane needs additional metadata to distinguish which resource in the + `ResourceList` is the composite resource and which are the composed + resources. + +### gVisor + +[gVisor][gvisor] supports rootless mode, but requires too many privileges to run +in a container. A proof-of-concept [exists][gvisor-unpriv] to add an +`--unprivileged` flag to gVisor, allowing it to run inside a container. It's +unlikely that gVisor will work in all situations in the near future - for +example gVisor cannot currently run inside gVisor and support for anything other +than x86 architectures is experimental. + +[term-composition]: https://crossplane.io/docs/v1.9/concepts/terminology.html#composition +[v0.10.0]: https://github.com/crossplane/crossplane/releases/tag/v0.10.0 +[composition-design]: https://github.com/crossplane/crossplane/blob/e02c7a3/design/design-doc-composition.md#goals +[declarative-app-management]: https://docs.google.com/document/d/1cLPGweVEYrVqQvBLJg6sxV-TrE5Rm2MNOBA_cxZP2WU/edit +[bcl]: https://twitter.com/bgrant0607/status/1123620689930358786?lang=en +[terraform-count]: https://www.terraform.io/language/meta-arguments/count +[turing-complete]: https://en.wikipedia.org/wiki/Turing_completeness#Unintentional_Turing_completeness +[pitfalls-dsl]: https://github.com/kubernetes/community/blob/8956bcd54dc6f99bcb681c79a7e5399289e15630/contributors/design-proposals/architecture/declarative-application-management.md#pitfalls-of-configuration-domain-specific-languages-dsls +[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime +[krm-fn-spec]: https://github.com/kubernetes-sigs/kustomize/blob/9d5491/cmd/config/docs/api-conventions/functions-spec.md +[rawextension]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#rawextension +[unix-domain-sockets]: https://man7.org/linux/man-pages/man7/unix.7.html +[rootless]: https://rootlesscontaine.rs/how-it-works/userns/ +[cgroups-v2-distros]: https://rootlesscontaine.rs/getting-started/common/cgroup2/#checking-whether-cgroup-v2-is-already-enabled +[overlayfs]: https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html +[go-containerregistry]: https://github.com/google/go-containerregistry +[oci-rt-cfg]: https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md +[oci-img-cfg]: https://github.com/opencontainers/image-spec/blob/v1.0.2/config.md +[gvisor-mountns]: https://github.com/google/gvisor/issues/221 +[kep-seccomp]: https://github.com/kubernetes/enhancements/issues/2413 +[package-meta]: https://github.com/crossplane/crossplane/blob/035e77b/design/one-pager-package-format-v2.md +[xpkg-spec]: https://github.com/crossplane/crossplane/blob/035e77b/docs/reference/xpkg.md +[attach]: https://github.com/kubernetes/kubectl/blob/18a531/pkg/cmd/attach/attach.go +[emissary]: https://github.com/argoproj/argo-workflows/blob/702b293/workflow/executor/emissary/emissary.go#L25 +[argo-deprecated-executors]: https://github.com/argoproj/argo-workflows/blob/v3.4.1/docs/workflow-executors.md +[krm-fn-spec]: https://github.com/kubernetes-sigs/kustomize/blob/9d5491/cmd/config/docs/api-conventions/functions-spec.md +[krm-fn-runtimes]: https://github.com/GoogleContainerTools/kpt/issues/2567 +[krm-fn-catalog]: https://catalog.kpt.dev +[gvisor]: https://gvisor.dev +[gvisor-unpriv]: https://github.com/google/gvisor/issues/4371#issuecomment-700917549 \ No newline at end of file diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 107ccef51..0083dcb95 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -1,8 +1,8 @@ - # Composition Functions + # Composition Functions: Beta -* Owners: Nic Cope (@negz), Sergen Yalçın (@sergenyalcin) -* Reviewers: Crossplane Maintainers -* Status: Draft +* Owners: Nic Cope (@negz) +* Reviewers: Hasan Turken (@turkenh), Jared Watts (@jbw976) +* Status: Accepted ## Background @@ -99,68 +99,76 @@ experiences designing Kubernetes, its precursor Borg, and many generations of configuration languages at Google, including [BCL/GCL][bcl]. In particular, we wanted to: -* Avoid organically growing a new DSL. These languages tend to devolve to - incoherency as stakeholders push to “bolt on” new functionality to solve - pressing problems at the expense of measured design. Terraform’s DSL - unintuitively [supporting the count argument in some places but not +* Avoid organically growing a new configuration Domain Specific Language (DSL). + These languages tend to devolve to incoherency as stakeholders push to “bolt + on” new functionality to solve pressing problems at the expense of measured + design. Terraform’s DSL [supporting the count argument in some places but not others][terraform-count] is a great example of this. Inventing a new DSL also comes with the cost of inventing new tooling to test, lint, generate, etc, your DSL. * Stick to configuration that could be modeled as a REST API. Modeling - Composition logic as a schemafied API resource makes it possible for - Crossplane to validate that logic and provide feedback to the platform team at - configuration time. It also greatly increases interoperability thanks to broad - support across tools and languages for interacting with REST APIs. - -It was also important to avoid the “worst of both worlds” - i.e. growing a fully -featured ([Turing-complete][turing-complete]) DSL modeled as a REST API. To this -end we omitted common language features such as conditionals and iteration. Our -rationale being that these features were better deferred to a General Purpose -Programming Language (GPL) designed by language experts, and with extensive -existing tooling. + Composition logic as a schemafied API resource makes it possible to validate + that logic and provide feedback to the platform team at configuration time. It + also greatly increases interoperability thanks to broad support across tools + and languages for interacting with REST APIs. + +It was also important to avoid the “worst of both worlds” - i.e. growing a new, +fully featured DSL modeled as a REST API. To this end we omitted common language +features such as conditionals and iteration. Our rationale being that these +features were better deferred to a General Purpose Programming Language (GPL) or +a mature, existing configuration DSL, with an established ecosystem of tooling +and documentation. Since its inception the Crossplane maintainers’ vision has been that there should essentially be two variants of Composition: * For simple cases, use contemporary "Patch and Transform" (P&T) Composition. -* For advanced cases, bring your tool or programming language of choice. - -In this context a “simple case” might involve composing fewer than ten resources -without the need for logic such as conditionals and iteration. Note that the -Composition logic, whether P&T or deferred to a tool or programming language, is -always behind the API line (behind an XR). This means the distinction is only -important to the people authoring the Compositions, never to the people -consuming them. - -Offering two variants of Composition allows Crossplane users to pick the one -that is best aligned with their situation, preferences, and experience level. -For simple cases you don’t need to learn a new programming language or tool, and -there are no external dependencies - just write familiar, Kubernetes-style YAML. -For advanced cases leverage proven tools and languages with existing ecosystems -and documentation. Either way, Crossplane has no religion - if you prefer not to -“write YAML”, pick another tool and vice versa. +* For advanced cases, use your DSL or GPL of choice. + +Note that the Composition logic (whether P&T, DSL, or GPL) is always "behind the +API line" (behind an XR). This means the distinction is only important to the +people _authoring_ the Compositions, never to the people consuming them. + +In the time since P&T Composition became available we've seen that: + +* Folks want to use Composition for more complex cases than we anticipated. Many + XRs fan out into tens of composed resources, sometimes nested. +* Many Compositions call for a high level of expressiveness - conditionals, + iteration, merging data from multiple fields, etc. +* The lack of a more expressive alternative to P&T Composition _has_ set us down + the path of organically growing a new DSL. (e.g. [#1972], [#2352], [#4051], + [#3917], [#3919], [#3989], [#3498], [#3458], [#3316], [#4036], [#4065], + [#4026]) +* Organically growing a new DSL is not only undesirable, but _slow_. Because + each addition to P&T Composition changes Crossplane's core API we must be + careful about what we accept. Changes take a long time to reach consensus. + They're coupled to Crossplane's release cycle, which means changes can take a + long time to become available, and aren't backported to older versions. +* How folks would ideally configure Composition varies. Some folks prefer a + particular configuration DSL, others look for webhooks written in a GPL, etc. + +To address these issues, we added support for 'Composition Functions' in +Crossplane v1.11. Functions are an alpha feature and are off by default. This +document is an iteration on (and supersedes) the [previous design +document][alpha-design] based on what we've learned during since the feature was +launched. ## Goals The proposal put forward by this document should: -* Let folks use their composition tool and/or programming language of choice. * Support 'advanced' composition logic such as loops and conditionals. -* Balance safety (e.g. sandboxing) with speed and simplicity. -* Be possible to introduce behind a feature flag that is off by default. +* Let folks specify Composition logic in their DSL or GPL of choice. +* Make it easy to extend Crossplane with new ways to 'do Composition'. +* Decouple adding new ways do 'do Composition' from the core release cycle. +* Be possible to keep behind a feature flag until it is generally available. While not an explicit goal, it would also be ideal if the solution put forth by -this document could serve as a test bed for new features in the contemporary -'resources array' based form of Composition. - -The user experience around authoring and maintaining Composition Functions is -out of scope for this proposal, which focuses only on adding foundational -support for the feature to Crossplane. +this document could serve as a test bed - and eventually replacement for - the +contemporary "patch and transform" form of Composition. ## Proposal -### Overview - This document proposes that a new `functions` array be added to the existing `Composition` type. This array of functions would be called either instead of or in addition to the existing `resources` array in order to determine how an XR @@ -175,24 +183,34 @@ metadata: name: example spec: compositeTypeRef: - apiVersion: database.example.org/v1alpha1 + apiVersion: database.example.org/v1 kind: XPostgreSQLInstance + # This Composition specifies functions instead of (P&T) resources. + # This is an array - you can specify a pipeline of Functions. functions: - - name: my-cool-function - type: Container - container: - image: xkpg.io/my-cool-function:0.1.0 + # Each entry in the functions array has a name. This uniquely identifies + # the Function 'call' within the Composition. + - name: compose-xr-using-go-templates + # The functionRef tells the Composition which Function to use. This Function + # uses Go Templates (like Helm) to render composed resources. + functionRef: + - name: go-templates + # A Function may optionally accept configuration. The configuration is + # passed to the Function when it is called. The configuration block looks + # like a nested custom resource - i.e. it has an apiVersion and kind. + config: + apiVersion: example.org/v1 + kind: GoTemplate + source: Remote + remote: git://github.com/example/my-xpostgresql-go-templates ``` -Under this proposal each function is the entrypoint of an OCI image, though the -API is designed to support different function implementations (such as webhooks) -in the future. The updated API would affect only the `Composition` type - no -changes would be required to the schema of `CompositeResourceDefinitions`, XRs, -etc. +The updated API would affect only the `Composition` type - no changes would be +required to the schema of `CompositeResourceDefinitions`, XRs, etc. -Notably the functions would not be responsible for interacting with the API -server to create, update, or delete composed resources. Instead, they instruct -Crossplane which resources should be created, updated, or deleted. +Notably the functions would not need to be responsible for interacting with the +API server to create, update, or delete composed resources. Instead, they +instruct Crossplane which resources should be created, updated, or deleted. Under the proposed design functions could also be used for purposes besides rendering composed resources, for example validating the results of the @@ -200,551 +218,767 @@ rendering composed resources, for example validating the results of the function could also be used to implement 'side effects' such as triggering a replication or backup. -Below is a more detailed example of an entry in the `functions` array. +Before you can use a Function, you must install it. Installing a Function works +just like installing a Provider: ```yaml -apiVersion: apiextensions.crossplane.io/v2alpha1 -kind: Composition +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function metadata: - name: example + name: go-templates spec: - compositeTypeRef: - apiVersion: database.example.org/v1alpha1 - kind: XPostgreSQLInstance - functions: - - name: my-cool-function - type: Container - # Configuration specific to `type: Container` functions. - container: - # The OCI image to pull and run. - image: xkpg.io/my-cool-function:0.1.0 - # Whether to pull the function Never, Always, or IfNotPresent. - imagePullPolicy: IfNotPresent - # Secrets used to pull from a private registry. - imagePullSecrets: - - namespace: crossplane-system - name: my-xpkg-io-creds - # Note that only resource limits are supported - not requests. - # The function will be run with the specified resource limits. - resources: - limits: - memory: 64Mi - cpu: 250m - # Defaults to 'Isolated' - i.e an isolated network namespace. - network: Accessible - # How long the function may run before it's killed. Defaults to 10s. - timeout: 30s - # Containers are run by an external process listening at the supplied - # endpoint. Specifying an endpoint is optional; the endpoint defaults to - # the below value. - runner: - endpoint: unix:///@crossplane/fn/default.sock - # An x-kubernetes-embedded-resource RawExtension (i.e. an unschemafied - # Kubernetes resource). Passed to the function as the config block of its - # FunctionIO. - config: - apiVersion: database.example.org/v1alpha1 - kind: Config - metadata: - name: cloudsql - spec: - version: POSTGRES_9_6 + package: xpkg.upbound.io/negz/go-templates:v0.1.0 ``` -### Function API +The Function package's `metadata.name` corresponds to the `functionRef` in the +previous example Composition. A Composition specifies which Function to run by +referencing the package's name. Like any other package, the `Function` type will +have a corresponding `FunctionRevision` type. -This document proposes that each function uses a `FunctionIO` type as its input -and output. In the case of `Container` functions this would correspond to stdin -and stdout. Crossplane would be responsible for reading stdout from the final -function and applying its changes to the relevant XR and composed resources. +### Calling a Function -```yaml -apiVersion: apiextensions.crossplane.io/v1alpha1 -kind: FunctionIO -config: - apiVersion: database.example.org/v1alpha1 - kind: Config - metadata: - name: cloudsql - spec: - version: POSTGRES_9_6 -observed: - composite: - resource: - apiVersion: database.example.org/v1alpha1 - kind: XPostgreSQLInstance - metadata: - name: my-db - spec: - parameters: - storageGB: 20 - compositionSelector: - matchLabels: - provider: gcp - status: - conditions: - - type: Ready - status: True - connectionDetails: - - name: uri - value: postgresql://db.example.org:5432 +Despite the name, a 'Function' is actually more like a 'function server'. Under +this proposal, Functions are long-running processes. When you install one, the +package manager deploys it using a Kubernetes Deployment - the same way it would +deploy a Provider. + + + +Crossplane makes a gRPC `RunFunctionRequest` to the Function it wishes to +invoke. The Function should respond with a `RunFunctionResponse`. These RPCs are +defined as follows: + +```protobuf +syntax = "proto3"; + +import "google/protobuf/struct.proto"; +import "google/protobuf/duration.proto"; + +// A FunctionRunnerService runs Composition Functions. +service FunctionRunnerService { + // RunFunction runs a Composition Function. + rpc RunFunction(RunFunctionRequest) returns (RunFunctionResponse) {} +} + +// A RunFunctionRequest requests that a Composition Function be run. +message RunFunctionRequest { + RequestMeta meta = 1; + + // The observed state prior to invocation of a Function pipeline. State passed + // to each Function is fresh as of the time the pipeline was invoked, not as + // of the time each Function was invoked. + State observed = 2; + + // Desired state according to a Function pipeline. The state passed to a + // particular Function may have been accumulated by processing a Composition's + // patch-and-transform resources array. It may also have been accumulated by + // previous Functions in the pipeline. Functions may mutate any part of the + // desired state they are concerned with, and must pass through any part of + // the desired state that they are not concerned with. + State desired = 3; + + // Configuration specific to this Function invocation. A JSON representation + // of the 'config' block of the relevant entry in a Composition's 'functions' + // array. + optional google.protobuf.Struct config = 4; +} + +// A RunFunctionResponse contains the result of a Composition Function run. +message RunFunctionResponse { + ResponseMeta meta = 1; + + // Desired state according to a Function pipeline. The state passed to a + // particular Function may have been accumulated by previous Functions in the + // pipeline. Functions may mutate any part of the desired state they are + // concerned with, and must pass through any part of the desired state that + // they are not concerned with. + State desired = 2; + + // Results of the Function run. Results may be used for observability and + // debugging purposes. + repeated Result results = 3; +} + +// RequestMeta contains metadata pertaining to a RunFunctionRequest. +message RequestMeta { + // An opaque string identifying the content of the request. Two identical + // requests should have the same tag. + string tag = 1; +} + +// ResponseMeta contains metadata pertaining to a RunFunctionResponse. +message ResponseMeta { + // An opaque string identifying the content of the request. + string tag = 1; + + // Time-to-live of this response. Idempotent functions with no side-effects + // (e.g. simple templating functions) may specify a TTL. Crossplane may choose + // to cache responses until the TTL expires. + optional google.protobuf.Duration ttl = 2; +} + +// State of the composite resource (XR) and any composed resources. +message State { + // The state of the composite resource (XR). + Resource composite = 1; + + // The state of any composed resources. + map resources = 2; +} + +// A Resource represents the state of a resource. +message Resource { + // The JSON representation of the resource. + google.protobuf.Struct resource = 1; + + // The resource's connection details. + map connection_details = 2; +} + +// A Result of running a Function. +message Result { + // Severity of this result. + // + // Fatal results are fatal; subsequent Composition Functions may run, but + // the Composition Function pipeline run will be considered a failure and + // the first fatal result will be returned as an error. + // + // Warning results are non-fatal; the entire Composition will run to + // completion but warning events and debug logs associated with the + // composite resource will be emitted. + // + // Normal results are emitted as normal events and debug logs associated + // with the composite resource. + Severity severity = 1; + + // Details about the result. + string message = 2; +} + +// Severity of Function results. +enum Severity { + SEVERITY_UNSPECIFIED = 0; + SEVERITY_FATAL = 1; + SEVERITY_WARNING = 2; + SEVERITY_NORMAL = 3; +}; ``` -A `FunctionIO` resource consists of the following top-level fields: - -* The `apiVersion` and `kind` (required). -* A `config` object (optional). This is a [Kubernetes resource][rawextension] - with an arbitrary schema that may be used to provide additional configuration - to a function. For example a `render-helm-chart` function might use its - `config` to specify which Helm chart to render. Functions need not return - their `config`, and any mutations will be ignored. -* An `observed` object (required). This reflects the observed state of the XR, - any existing composed resources, and their connection details. Functions must - return the `observed` object unmodified. -* A `desired` object (optional). This reflects the accumulated desired state of - the XR and any composed resources. Functions may mutate the `desired` object. -* A `results` array (optional). Used to communicate information about the result - of a function, including warnings and errors. Functions may mutate the - `results` object. - -Each function takes its `config` (if any), `observed` state, and any previously -accumulated `desired` state as input, and optionally mutates the `desired` -state. This allows the output of one function to be the input to the next. - -The `observed` object consists of: - -* `observed.composite.resource`. The observed XR. -* `observed.composite.connectionDetails`: The observed XR connection details. -* `observed.resources[N].name`: The name of an observed composed resource. -* `observed.resources[N].resource`: An observed composed resource. -* `observed.resources[N].connectionDetails`: An observed composed resource's - current connection details. - -If an observed composed resource appears in the Composition's `spec.resources` -array their `name` fields will match. Note that the `name` field is distinct -from a composed resource's `metadata.name` - it is used to identify the resource -within a Composition and/or its function pipeline. - -The `desired` object consists of: - -* `desired.composite.resource`. The desired XR. -* `desired.composite.resource.connectionDetails`. Desired XR connection details. -* `desired.resources[N].name`. The name of a desired composed resource. -* `desired.resources[N].resource`. A desired composed resource. -* `desired.resources[N].connectionDetails`. A desired composed resource's - connection details. -* `desired.resources[N].readinessChecks`. A desired composed resource's - readiness checks. - -Note that the `desired.resources` array of the `FunctionIO` type is very -similar to the `spec.resources` array of the `Composition` type. In comparison: - -* `name` works the same across both types, but is required by `FunctionIO`. -* `connectionDetails` and `readinessChecks` work the same across both types. -* `FunctionIO` does not support `base` and `patches`. Instead, a function should - configure the `resource` field accordingly. - -The `desired` state is _accumulated_ across the Composition and all of its -functions. This means the first function may be passed desired state as -specified by the `spec.resources` array of a Composite, if any, and each -function must include the accumulated desired state in its output. Desired state -is treated as an overlay on observed state, so a function pipeline need not -specify the desired state of the XR (for example) unless a function wishes to -mutate it. - -A full `FunctionIO` specification will accompany the implementation. Some -example scenarios are illustrated below. - -A function that wanted to create (compose) a `CloudSQLInstance` would do so by -returning the following `FunctionIO`: +This RPC is essentially the `RunFunctionRequest` from the [alpha Functions +design][alpha-design] with the `FunctionIO` elevated from opaque YAML-encoded +bytes to 'native' RPC code. + +The package manager is responsible for creating a headless Kubernetes Service +where each Function's Deployment can be reached. The address of the Service will +be exposed as the `status.endpoint` of the Function resource. The service must +be headless in order for Crossplane's gRPC client to load-balance connections +when there are multiple Function replicas. + +Note that the fact this endpoint is powered by a Service is an implementation +detail; it may be possible for Functions to be reached (and indeed deployed) by +other means in future. ```yaml -apiVersion: apiextensions.crossplane.io/v1alpha1 -kind: FunctionIO -observed: {} # Omitted for brevity. -desired: - resources: - - name: cloudsqlinstance - resource: - apiVersion: database.gcp.crossplane.io/v1beta1 - kind: CloudSQLInstance - spec: - forProvider: - databaseVersion: POSTGRES_9_6 - region: us-central1 - settings: - tier: db-custom-1-3840 - dataDiskType: PD_SSD - dataDiskSizeGb: 20 - writeConnectionSecretToRef: - namespace: crossplane-system - name: cloudsqlpostgresql-conn - connectionDetails: - - name: hostname - fromConnectionSecretKey: hostname - readinessChecks: - - type: None +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: go-templates +spec: + package: xpkg.upbound.io/negz/go-templates:v0.1.0 +status: + # The gRPC endpoint where Crossplane will send RunFunctionRequests. + endpoint: https://go-templates-9sdfn2 ``` -A function that wanted to set only an XR connection detail could return: +gRPC communication between Crossplane and a Function will be secured by mutual +transport layer security (mTLS). Crossplane has an established pattern for +setting up mTLS certificate bundles - we do this today to secure communication +between the API server and our validation webhooks, and between Crossplane and +External Secret Stores. We might want to [rethink this][cert-per-entity] in +future, but to begin with we'll stick with the established pattern, i.e.: -```yaml -apiVersion: apiextensions.crossplane.io/v1alpha1 -kind: FunctionIO -observed: {} # Omitted for brevity. -desired: - composite: - connectionDetails: - - type: FromValue - name: username - value: admin +* The Helm chart creates an empty Secret for the client bundle. +* The core init container bootstraps the client bundle. +* The package manager creates a Secret for each Function's server bundle. +* The package manager bootstraps each Function's server bundle. + +See [#3884] for an example of this pattern. + +The frequency with which Crossplane will call each Function is relative to how +frequently each XR is reconciled. There are two main triggers to reconcile an XR: + +1. A watch-triggered reconcile, i.e. because the XR changed. +2. A poll-triggered reconcile, by default once per 60 seconds. + +XRs rely on poll-triggered reconciliation to promptly correct drift of their +composed resources. Ideally XR reconciliation would be purely watch-triggered, +but this would require dynamically adding and removing watches as the types of +resources the XR composes changes. The poll interval can be set using the +`--poll-interval` flag. + +Assume: + +* There are 100 XRs, all of the same type, and all using the same Composition. +* The XRs have all reached a steady state, polling at the default 60s frequency. +* The Composition includes 1 Function call. + +In this case the Function would be called __100 * 1 = 100 times per 60s__. + +A few approaches are possible to scale Functions: + +* Tune the `--poll-interval`, e.g. to every 5m or 10m. +* Scale heavily used Functions horizontally, by increasing Deployment replicas. +* Cache the responses of idempotent Function calls. + +The `RunFunctionRequest` includes a `meta.tag` field to assist with caching. The +tag identifies a unique Function input. How the tag is generated is up to the +caller (i.e. Crossplane), but two functionally identical Function inputs should +have the same tag. A Function can optionally signal that its response is valid +for the same input for a period of time by returning a non-zero `meta.ttl`. This +allows Crossplane (or an intermediary such as a reverse proxy) to cache the +responses of idempotent and side-effect-less Functions. + +### Developing a Function + +I believe it's critical that Composition Functions are easy to develop - much +easier than developing a Crossplane Provider. + +Not everyone will want or need to develop Functions. Some Functions will be +_generic_. A generic Function would be able to work with any kind of XR. +Consider for example a `go-templates` Function that effectively "outsourced" the +entire Composition logic of an XR to a set of Go templates - a familiar +authoring experience to anyone who has used Helm. + +Despite the potential for generic Functions, I feel it must be easy to "roll +your own" because: + +* We want to make it really easy to make new generic Functions! The easier + Functions are to build, the more community members can contribute to the + ecosystem. +* Sometimes there won't be a perfect Function for your unique use-case. The + easier Functions are to build, the more likely you are to be able to help + yourself. +* Some folks just _prefer_ to configure how to take an XR and produce a set of + composed resources using the expressiveness and familiarity of a + general-purpose programming language. The more complex your Composition logic + becomes, the more appealing this approach is. + +I propose we do three things to make Functions easy to develop: + +1. Provide SDKs for popular languages - e.g. Go, Python, TypeScript. +2. Provider tooling to scaffold, build, push, and test Functions. +3. Support providing Function logic as an OCI container that runs to completion. + +Consider this section a medium-resolution sketch of the Function development +experience. Likely each of these components (tooling, SDKs, etc) warrant at +least a one-pager of their own, and they may not look exactly as proposed here. +This section intends only to paint a picture of what Functions enable. + +#### Use Language SDKs + +Consider for example the following experience for writing a Go Function. Keep in +mind a similar experience would also exist for other languages. + +```shell +# Initialize a new function that uses the Go SDK. +$ kubectl crossplane init function --template="github.com/crossplane/fn-template-go" + +# This generates boilerplate that uses the Go SDK. +$ ls +crossplane.yaml fn.go fn_test.go go.mod main.go + +# At a minimum you need to add your Function logic to fn.go +vim fn.go ``` -A function wishing to delete a composed resource may do so by setting its -`resource` to null, for example: +Note that Functions have package metadata (in `crossplane.yaml` by convention) +just like a Provider or Configuration. A Function may declare dependencies - for +example a Function could depend on a Provider to indicate that it composes that +Provider's MRs. -```yaml -apiVersion: apiextensions.crossplane.io/v1alpha1 -kind: FunctionIO -observed: {} # Omitted for brevity. -desired: - resources: - - name: cloudsqlinstance - resource: null +After you initialize a function using the Go SDK you must update fn.go to +provide your composition logic. When you first open fn.go you’ll see that +`kubectl crossplane init function` added boilerplate like this: + +```go +package main + +import ( + "context" + + function "github.com/crossplane/fn-sdk-go" + "github.com/crossplane/fn-sdk-go/pb" + "github.com/crossplane/fn-sdk-go/errors" +) + +// Function defines the logic of your Function. +func Function(ctx context.Context, req *pb.RunFunctionRequest) (*pb.RunFunctionResponse, error) { + // Get the desired XR from the request. + xr := function.NewEmptyCompositeResource() + if err := function.GetCompositeResource(req, xr); err != nil { + return errors.Wrap(err, "could not get composite resource") + } + + // TODO: Replace this with your function logic. :) + rsp := function.NewResponseTo(req) + function.Normalf(rsp, "successfully read desired composite resource %q", xr.GetName()) + + return rsp, nil +} ``` -A function that could not complete successfully could do so by returning the -following `FunctionIO`: +To write a function, replace the boilerplate with your own logic. Here’s an +example that uses a mockup of a Go SDK to achieve the same goal as lab 4 from +[the Kubecon EU ContribFest][kubecon-eu-contribfest]. ```yaml -apiVersion: apiextensions.crossplane.io/v1alpha1 -kind: FunctionIO -config: - apiVersion: database.example.org/v1alpha1 - kind: Config - metadata: - name: cloudsql - spec: - version: POSTGRES_9_6 -observed: {} # Omitted for brevity. -results: -- severity: Error - message: "Could not render Database.postgresql.crossplane.io/v1beta1` +apiVersion: contribfest.crossplane.io/v1alpha1 +kind: XRobotGroup +metadata: + name: somename +spec: + count: 5 ``` -### Running Container Function Pipelines +This example takes an XR like the preceding one and uses its `spec.count` to +compose the desired number of Robot resources: -While Crossplane typically runs in a Kubernetes cluster - a cluster designed to -run containers - running an ordered _pipeline_ of short-lived containers via -Kubernetes is much less straightforward than you might expect. Refer to -[Alternatives Considered](#alternatives-considered) for details. +```go +package main -In order to provide flexibility and choice of tradeoffs in running containers -(e.g. speed, scalability, security) this document proposes Crossplane defer -containerized functions to an external runner. Communication with the runner -would occur via a gRPC API, with the runner expected to be listening at the -`endpoint` specified via the function's `runner` configuration block. This -endpoint would default to `unix:///@crossplane/fn/default.sock` - an abstract -[Unix domain socket][unix-domain-sockets]. +import ( + "context" + "fmt" + "math/rand" -Communication between Crossplane and a containerized function runner would use -the following API: + "github.com/upbound/provider-dummy/apis/iam/v1alpha1" -```protobuf -syntax = "proto3"; + function "github.com/crossplane/fn-sdk-go" + "github.com/crossplane/fn-sdk-go/pb" + "github.com/crossplane/fn-sdk-go/errors" +) -// This service defines the APIs for a containerized function runner. -service ContainerizedFunctionRunner { - rpc RunFunction(RunFunctionRequest) returns (RunFunctionResponse) {} -} +var colors = []string{"red", "green", "blue", "yellow", "orange"} -// Corresponds to Kubernetes' image pull policy. -enum ImagePullPolicy { - IF_NOT_PRESENT = 0; - ALWAYS = 1; - NEVER = 2; -} +// Function defines the logic of your Function. +func Function(ctx context.Context, req *pb.RunFunctionRequest) (*pb.RunFunctionResponse, error) { + // Get the desired XR from the request. + xr := function.NewEmptyCompositeResource() + function.GetCompositeResource(req, xr) -// Corresponds to go-containerregistry's AuthConfig type. -// https://pkg.go.dev/github.com/google/go-containerregistry@v0.11.0/pkg/authn#AuthConfig -message ImagePullAuth { - string username = 1; - string password = 2; - string auth = 3; - string identity_token = 4; - string registry_token = 5; -} + // Get the desired resource count from the XR. + count, err := xr.GetInteger("spec.count") + if err != nil { + return errors.Wrap(err, "could not get desired resource count") + } -message ImagePullConfig { - ImagePullPolicy pull_policy = 1; - ImagePullAuth auth = 2; -} + // Create a response to return. This deep-copies any existing desired state. + rsp := function.NewResponseTo(req) -// Containers are run without network access (in an isolated network namespace) -// by default. -enum NetworkPolicy = { - ISOLATED = 0; - ACCESSIBLE = 1; -} + // Ensure the desired number of robots exist. + for i := 0; i < int(count); i++ { + name := fmt.Sprintf("robot-%d") -// Only resource limits are supported. Resource requests could be added in -// future if a runner supported them (e.g. by running containers on Kubernetes). -message Resources { - ResourceLimits limits = 1; -} + // Get the desired composed resource (if any) from the request. + // Since we're using Go we can import and work with API types if we want. + robot := &v1alpha1.Robot{} + function.GetComposedResource(req, name, robot) -message ResourceLimits { - string memory = 1; - string cpu = 2; -} + // The robot's external name should be derived from the XR's. + function.SetExternalName(robot, fmt.Sprintf("%s-%s", function.GetExternalName(xr), name)) -message RunFunctionConfig { - Resources resources = 1; - NetworkPolicy network = 2; - Duration timeout = 3; -} + // Give this robot a random color! + if robot.Spec.ForProvider.Color != "" { + c := colors[rant.Intn(len(colors))] + robot.Spec.ForProvider.Color = c -// The input FunctionIO is supplied as opaque bytes. -message RunFunctionRequest { - string image = 1; - bytes input = 2; - ImagePullConfig = 3; - RunFunctionConfig = 4; -} + // Add a result indicating that we set the color. Crossplane will + // surface this as a Kubernetes event and a debug log. + function.Normalf(rsp, "set robot %q color to %q", name, c) + } -// The output FunctionIO is supplied as opaque bytes. Errors encountered while -// running a function (as opposed to errors returned _by_ a function) will be -// encapsulated as gRPC errors. -message RunFunctionResponse { - bytes output = 1; + // Set our new desired robot state. This will be a no-op if our robot + // already existed. + function.SetComposedResource(rsp, name, robot) + } + + return rsp, nil } ``` -### The Default Function Runner - -This document proposes that Crossplane include a default function runner. This -runner would be implemented as a sidecar to the core Crossplane container that -runs functions inside itself. - -The primary advantages of this approach are speed and control. There's no need -to wait for another system (for example the Kubernetes control plane) to -schedule each container, and the runner can easily pass stdout from one -container to another's stdin. Speed of function runs is of particular importance -given that each XR typically reconciles (i.e. invokes its function pipeline) -once every 60 seconds. - -The disadvantages of running the pipeline inside a sidecar container are scale -and reinvention of the wheel. The resources available to the sidecar container -will bound how many functions it can run at any one time, and it will need to -handle features that the Kubelet already offers such as pull secrets, caching -etc. - -[Rootless containers][rootless] appear to be the most promising way to run -functions as containers inside a container: - -> Rootless containers uses `user_namespaces(7)` (UserNS) for emulating fake -> privileges that are enough to create containers. The pseudo-root user gains -> capabilities such as `CAP_SYS_ADMIN` and `CAP_NET_ADMIN` inside UserNS to -> perform fake-privileged operations such as creating mount namespaces, network -> namespaces, and creating TAP devices. - -Using user namespaces allows the runner to use the other kinds of namespaces -listed above to ensure an extra layer of isolation for the functions it runs. -For example a network namespace could be configured to prevent a function having -network access. - -User namespaces are well supported by modern Linux Kernels, having been -introduced in Linux 3.8. Many OCI runtimes (including `runc`, `crun`, and -`runsc`) support rootless mode. `crun` appears to be the most promising choice -because: - -* It is more self-contained than `runc` (the reference and most commonly used - OCI runtime), which relies on setuid binaries to setup user namespaces. -* `runsc` (aka gVisor) uses extra defense in depth features which are not - allowed inside most containers due to their seccomp policies. - -Of course, "a container" is in fact many technologies working together and some -parts of rootless containers are less well supported than others; for example -cgroups v2 is required in order to limit resources like CPU and memory available -to a particular function. cgroups v2 has been available in Linux since 4.15, but -was not enabled by many distributions until 2021. In practice this means -Crossplane users must use a [sufficiently modern][cgroups-v2-distros] -distribution on their Kubernetes nodes in order to constrain the resources of a -Composition function. - -Similarly, [overlayfs] was not allowed inside user namespaces until Linux 5.11. -Overlayfs is typically used to create a root filesystem for a container that is -backed by a read-write 'upper' directory overlaid on a read-only 'lower' -directory. This allows the root OCI image filesystem to persist as a cache of -sorts, while changes made during the lifetime of a container can be easily -discarded. It's possible to replicate these benefits (at the expense of disk -usage and start-up time) by falling back to making a throwaway copy of the root -filesystem for each container run where overlayfs is not available. - -Under the approach proposed by this document each function run would involve the -following steps: - -1. Use [go-containerregistry] to pull the function's OCI image. -1. Extract (untar) the OCI image's flattened filesystem to disk. -1. Create a filesystem for the container - either an overlay or a copy of the - filesystem extracted in step 2. -1. Derive an [OCI runtime configuration][oci-rt-cfg] from the - [OCI image configuration][oci-img-cfg] supplied by go-containerregistry. -1. Execute `crun run` to invoke the function in a rootless container. - -Executing `crun` directly as opposed to using a higher level tool like `docker` -or `podman` allows the default function runner to avoid new dependencies apart -from a single static binary (i.e. `crun`). It keeps most functionality (pulling -images etc) inside the runner's codebase, delegating only container creation to -an external tool. Composition Functions are always short-lived and should always -have their stdin and stdout attached to the runner, so wrappers like -`containerd-shim` or `conmon` should not be required. The short-lived, "one -shot" nature of Composition Functions means it should also be acceptable to -`crun run` the container rather than using `crun create`, `crun start`, etc. - -At the time of writing rootless containers appear to be supported by Kubernetes, -including Amazon's Elastic Kubernetes Service (EKS) and Google Kubernetes Engine -(GKE). - -Testing using GKE 1.21.10-gke.2000 with Container Optimized OS (with containerd) -cos-89-16108-604-19 nodes (Kernel COS-5.4.170) found that it was possible to run -`unshare -rUm` (i.e. to create a new user and mount namespace) inside an Alpine -Linux container as long as AppArmor was disabled by applying the annotation -`container.apparmor.security.beta.kubernetes.io/${CONTAINER_NAME}=unconfined`. -It's possible to create user namespaces with AppArmor enabled, but not to create -mount namespaces with different mount propagation from their parent. - -It is not possible to use rootless containers with gVisor enabled, as gVisor -does not yet [support mount namespaces][gvisor-mountns]. This means that it is -not possible to use rootless containers with GKE Autopilot, which requires that -gVisor be used. - -Testing using EKS v1.21.5-eks-9017834 with Amazon Linux 2 nodes (Kernel -5.4.188-104.359.amzn2.x86_64) found that it was possible to run `unshare -rUm` -inside an Alpine Linux container 'out of the box'. - -The `unshare` syscall used to create containers is rejected by the default -Docker and containerd seccomp profiles. seccomp is disabled ("Unconstrained") by -default in Kubernetes, but that will soon change per [this KEP][kep-seccomp] -which proposes that Kubernetes use the seccomp profiles of its container engine -(i.e. containerd) by default. Once this happens Crossplane will either need to -run with the "Unconstrained" seccomp profile, or a variant of the default -containerd seccomp profile that allows a few extra syscalls (i.e. at least -`unshare` and `mount`). This can be done by setting a Pod's -`spec.securityContext.seccompProfile.type` field to `Unconstrained`. - -### Packaging Containerized Functions - -This document proposes that containerized functions support Crossplane [package -metadata][package-meta] in the form of a `package.yaml` file at the root of the -flattened filesystem and/or the OCI layer annotated as `io.crossplane.xpkg: -base` per the [xpkg spec][xpkg-spec]. This `package.yaml` file would contain a -custom-resource-like YAML document of type `Function.meta.pkg.crossplane.io`. - -Unlike `Configuration` and `Provider` packages, `Function` packages would not -actually be processed by the Crossplane package manager but rather by the -Composition (`apiextensions`) machinery. In practice Crossplane would be -ignorant of the `package.yaml` file; it would exist purely as a way to attach -"package-like" metadata to containerized Crossplane functions. Therefore, unlike -the existing package types the `package.yaml` would contain no `spec` section. - -An example `package.yaml` might look like: +The goals of a Composition Function SDK are to: + +* Expose an API that makes writing Functions intuitive and self-documenting. +* Steer Function authors toward best practices, and away from anti-patterns. +* Eliminate boilerplate, like setting up a gRPC server. + +This mockup only touches on very basic functionality. A fully featured SDK would +cover more use cases - for example reading Function-specific config and working +with connection details. + +Once you’ve written your Function code you can test it using the tooling for +your chosen language - in this case `go test`. `kubectl crossplane` would create +boilerplate for unit tests. + +You build and push a Function just like you would a Provider or Configuration. +There are already GitHub Actions that allow this to be done as part of a CI/CD +pipeline. + +```shell +# Building the Function produces an installable Function package. +$ kubectl crossplane function build + +# Push the package to any OCI registry. +$ kubectl crossplane function push xpkg.upbound.io/negz/function-many-robots:v0.1.0 +``` + +Note that leveraging gRPC makes it possible to generate server stubs for [many +languages][grpc-supported-languages]. I would not consider these server stubs to +be 'an SDK' - they don't make writing Functions intuitive and self-documenting, +or steer Function authors toward best practices. They do however go a long way +toward eliminating boilerplate, including generating language-specific +representations of a `RunFunctionRequest` and `RunFunctionResponse`. + +#### Use an OCI Container + +In the [alpha iteration of Composition Functions][alpha-design] all functions +are binaries that run to completion. These processes are packaged as an OCI +container. A sidecar container in the Crossplane pod - `xfn` - runs each of them +in a rootless container. + +This doesn't scale very well, but it does offer a way to build a Function for +folks who don't want to write code; you can get a long way just using a tool +like https://github.com/mikefarah/yq. It also offers a way to build Functions in +languages that don't have a 'first class' SDK available. Think of this like AWS +Lambda, which supports 9-10 first class languages, and OCI containers as a +catch-all for everything else. + +I propose we move the `xfn` function runner out of crossplane/crossplane, +simplify it, and offer it as an alternative way to build a Function. You could +think of this as a special kind of Composition Function SDK that builds a +Composition Function from an OCI container, rather than building a Function a +literal _function_ (e.g. written in Go). + + + +Under this design each containerized Function is "wrapped" in an `xfn`-like +Composition Function. This means each Function exists as its own Deployment. + +This design merges the Protobuf `RunFunctionRequest` with the YAML `FunctionIO` +types from the alpha design, so instead of reading a `FunctionIO` from stdin a +containerized Function would read a JSON-encoded `RunFunctionRequest`, and write +a `RunFunctionResponse` to stdout. + +Building a containerized Function would work as follows. + +Start with a simple container that reads a JSON `RunFunctionRequest` on stdin +and writes a JSON `RunFunctionResponse` to stdout. This one simply adds a label +(credit to @pedjak in https://github.com/crossplane/crossplane/issues/4293) for +the idea). + +```Dockerfile +FROM alpine:3.18 +RUN apk add --no-cache jq +ENTRYPOINT ["/bin/sh", "-c", "jq '(.desired.resources[] | .resource.metadata.labels) |= {\"labelizer.xfn.crossplane.io/processed\": \"true\"} + .' | .desired.resources"] +``` + +Then build a Function from the image. We want the image to run in its own +container, nested inside the Function container. This allows the OCI container +to run within its own namespaces without interfering with (or being interfered +with by) the `xfn`-like 'adaptor'. To do this we bake the container into the +Function artifact: + +```shell +# Build your OCI image. +$ docker build . +Successfully built 202dc6e5df4c + +# Save your OCI image to a tarball. +$ docker save | gzip > function.tgz + +# Add some package metadata for your Function. +$ vim crossplane.yaml + +# Build a Function from the tarball. +$ kubectl crossplane function build --from-oci-tarball=function.tgz + +# Push the package to any OCI registry. +$ kubectl crossplane function push xpkg.upbound.io/negz/function-labelizer:v0.1.0 +``` + +The `function build --from-oci-tarball` command creates a Function powered by an +`xfn`-like adaptor that: + +1. Prepares an OCI runtime bundle from the supplied tarball at startup. +2. Listens for `RunFunctionRequest` RPCs. +3. Prepares `RunFunctionResponse` RPCs by using an OCI runtime (e.g. `crun`) to + invoke the embedded Function in a rootless container. + +Note that most of this functionality already exists in `xfn`. This makes it +cheap enough to implement this Function variant that I believe it's worth doing, +even if it ends up covering a relatively niche case. + +### Using a Function + +Composition Functions are very flexible, so the user experience could vary a +lot. However the general pattern is: + +1. Find (or build!) a Function you want to use. +2. Install the Function using the package manager. +3. Include the Function (and any Function config) in a Composition. + +Again, consider this section a medium-resolution sketch of the Function +experience. The generic Functions demonstrates here don't actually exist (yet!). +They may not look exactly as proposed here. This section intends only to paint a +picture of what Functions enable. + +Consider the hypothetical generic "Go templates" Function put forward at the +[beginning of this proposal][#proposal]. Such a Function would make it possible +to write a Composition that used familiar, Helm-like moustache templates with +support for iteration and conditionals. + +If we take the [contribfest][kubecon-eu-contribfest] example again, this might +look something like this: ```yaml -# Required. Must be as below. -apiVersion: meta.pkg.crossplane.io/v1alpha1 -# Required. Must be as below. -kind: Function -# Required. +apiVersion: apiextensions.crossplane.io/v2alpha1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: database.example.org/v1 + kind: XPostgreSQLInstance + functions: + - name: compose-xr-using-go-templates + functionRef: + name: go-templates + config: + apiVersion: example.org/v1 + kind: GoTemplate + source: Inline # Or Remote, if you want to pull templates from git. + inline: | + {{- range $i := until ( . desired.composite.resource.spec.count ) }} + --- + apiVersion: iam.dummy.upbound.io/v1alpha1 + kind: Robot + metadata: + annotations: + crossplane.io/external-name: {{ .desired.composite.resource | getExternalName }}-robot-{{ $i }} + spec: + forProvider: + {{- if $i | printf "robot-%d" | getComposedResource }} + # This resource already exists - use the same color. + color: {{ .spec.forProvider.color }} + {{ else }} + # The robot doesn't exist. Pick a new color. + color: {{ randomChoice "red" "green" "blue }} + {{- end }} + {{- end }} +``` + +This example is functionally identical to [the Go example][#use-language-sdks], +but uses a DSL - Go templates with http://masterminds.github.io/sprig/ and a +few Crossplane-specific functions. Indeed this Function could be built using the +Go SDK - a generic Function for anyone who prefers Go Templates. + +Here's another example of a generic Function. This one lets Composition authors +express their Composition logic in arbitrary, inline [Starlark][starlark]. + +```yaml +apiVersion: apiextensions.crossplane.io/v2alpha1 +kind: Composition metadata: - # Required. Must comply with Kubernetes API conventions. - name: function-example - # Optional. Must comply with Kubernetes API conventions. - annotations: - meta.crossplane.io/source: https://github.com/negz/example-fn - meta.crossplane.io/description: An example function + name: example +spec: + compositeTypeRef: + apiVersion: database.example.org/v1 + kind: XPostgreSQLInstance + functions: + - name: compose-xr-using-go-templates + functionRef: + name: starlark + config: + apiVersion: example.org/v1 + kind: StarlarkScript + script: | + # main is passed a RunFunctionRequest as a (Python-like) dictionary. + # It must return a RunFunctionResponse-shaped dictionary. + def main(req): + rsp = {desired=req["desired"], results=req["results]} + xr = req["observed"]["composite"]["resource"] + + for i in range(int(xr["spec"]["count"])): + name = "robot-{}".format(i) + + # We already created this one during a previous reconcile. + if name in req["observed"]["resources"]: + rsp["desired"]["resources"][name] = req["observed"]["resources"][name] + continue + + # This robot should exist, but doesn't. + rsp["desired"]["resources"][name] = { + "resource": { + "apiVersion": "iam.dummy.upbound.io/v1alpha1", + "kind": "Robot", + "metadata": { + "annotations": { + "crossplane.io/external-name": "{parent}-robot-{number}".format( + parent=xr["metadata"]["annotations"]["crossplane.io/external-name"], + number=i, + ) + }, + }, + "spec": { + "forProvider": { + # Starlark is deterministic so these Robots are always purple. :) + "color": "purple", + }, + }, + } + } + + return rsp +``` + +Starlark is a (very) limited dialect of Python designed configuration. It embeds +into many languages - including Go. This makes it a great candidate to build a +generic Function that allows Composition authors to provide _inline_ logic in a +general-purpose-esque programming language. This is similar to the ["GitHub +Script"][github-script] GitHub Action that lets you plug some arbitrary logic +into a GitHub Action pipeline when no existing Action does quite what you need. + +### Iterating on Compositions that use Functions + +Getting fast feedback on a Crossplane Composition has historically been a pain +because the Composition logic has been encapsulated in a Kubernetes controller. +In order to know whether your Composition works as intended you need to: + +1. Deploy (the right version of!) Crossplane to a Kubernetes cluster. +2. Install Providers and Configurations for any resources you want to compose. +3. Apply your XRD and Composition (potentially via a Configuration). +4. Create an XR (or claim). +5. See whether it works. + +Moving Composition logic out of Crossplane and into versioned Functions makes it +a lot easier to test and iterate on, client-side. For example a `function test` +command could test a single function in isolation: + +```shell +# Test a single Function by passing it a JSON RunFunctionRequest. This pulls and +# starts the function, makes the request, stops it, then returns the result. +$ kubectl crossplane function test xpkg.upbound.io/negz/go-templates:v0.1.0 run-function-request.json +{ + # JSON encoded RunFunctionResponse omitted for brevity. +} ``` -## Alternatives Considered +You could similarly imagine a more holistic, `helm template`-like experience +that locally rendered an entire Composition by pulling and running its templates +locally: + +```shell +$ kubectl crossplane composition render composition.yaml xr.yaml +--- +# YAML stream omitted for brevity. +``` + +Assuming a 'pure' Composition consisting only of Functions with no P&T +resources, this command would need only to iterate through the Composition's +`functions` array, and for each Function: + +1. Pull and start it. +2. Form a `RunFunctionRequest` from the XR and any prior `RunFunctionResponse`. +3. Print the `desired` block of final `RunFunctionResponse` as a YAML stream. + +This isn't quite an end-to-end test of Composition. The composed resources are +not actually created and reconciled with an external system, so its not possible +for example to derive XR status from composed resource status. It's also not +possible in isolation to determine whether the rendered composed resources are +schematically valid. It does however give you a good idea of whether your +Composition will produce the set of composed resources that you'd expect - just +like `helm template`. + +The advantage of Functions in this regard is that the `composition render` +command would need to duplicate much less code from the Crossplane Composition +controller than if it were to try to recreate the built-in P&T logic. -Most of the alternatives considered in this design could also be thought of as -future considerations. In most cases these alternatives don't make sense at the -present time but likely will in the future. +### Future Improvements -### Using Webhooks to Run Functions +The following functionality is out-of-scope for the beta implementation, but may +be added in future. -Crossplane could invoke functions by calling a webhook rather than running an -OCI container. In this model function input and output would still take the form -of a `FunctionIO`, but would be HTTP request and response bodies rather than a -container's stdin and stdout. +#### Function Config Custom Resources + +In the current alpha implementation of Functions, and this design, Function +configuration is a custom-resource-like inline resource (i.e. an +`x-kubernetes-embedded-resource`): + +```yaml + functions: + - name: compose-xr-using-go-templates + functionRef: + name: starlark + config: + apiVersion: example.org/v1 + kind: StarlarkScript + script: ... +``` + +In future it may be useful for a Function to be able to deliver this type as a +custom resource definition (CRD). This would allow a single configuration to be +more easily shared by multiple Compositions. A Composition could reference a +Function configuration: + +```yaml + functions: + - name: compose-xr-using-go-templates + functionRef: + name: starlark + configRef: + apiVersion: example.org/v1 + kind: StarlarkScript + name: make-some-purple-robots +``` -The primary detractor of this approach is the burden it puts on function authors -and Crossplane operators. Rather than simply publishing an OCI image the author -and/or Crossplane operator must deploy and operate a web server, ensuring secure -communication between Crossplane and the webhook endpoint. +At this stage I suggest holding off on building this functionality until there +is clear demand. -Support for `type: Webhook` functions will likely be added shortly after initial -support for `type: Container` functions is released. +#### Metrics and Tracing -### Using chroots to Run Functions +Crossplane does not currently expose its own metrics. It relies on [the set +it gets from controller-runtime][controller-runtime-metrics], and metrics that +may be [derived from the Kubernetes events it emits][event-exporter-metrics]. -Crossplane could invoke functions packaged as OCI images by unarchiving them and -then running them inside a simple `chroot`. This offers more compatibility than -rootless containers at the expense of isolation - it's not possible to constrain -a chrooted function's compute resources, network access, etc. `type: Chroot` -functions would use the same artifacts as `type: Container` functions but invoke -them differently. +These metrics pertain to Kubernetes controllers, and will be insufficient when a +significant portion of Composition logic is 'outsourced' to Functions. It will +be important to establish a pattern for instrumenting Functions (e.g. as part of +the Function SDKs). Request tracing in particular is likely to be useful in +order to debug slow or failing Functions in a pipeline. -Support for `type: Chroot` functions could be added shortly after initial -support for `type: Container` functions are released if `type: Container` proves -to be insufficiently compatible (e.g. for clusters running gVisor, or that -require seccomp be enabled). +Metrics and tracing for Functions must be implemented before the feature becomes +generally available (GA). -### Using Kubernetes to Run Containerized Functions +#### Caching -Asking Kubernetes to run a container pipeline is less straightforward than you -might think. Crossplane could schedule a `Pod` for each XR reconcile, or create -a `CronJob` to do so regularly. Another option could be to connect directly to a -Kubelet. This approach would enjoy all the advantages of the existing Kubelet -machinery (pull secrets, caching, etc) but incurs overhead in other areas, for -example: +The gRPC API proposed by this design accomodates caching, but building caching +support is not in scope for beta. This will likely be a requirement for GA. -* Every reconcile requires a pod to be scheduled, which may potentially block on - node scale-up, etc. -* stdin and stdout must be streamed via the API server, for example by using the - [`/attach` subresource][attach]. -* Running containers in order requires either (ab)using init containers or - injecting a middleware binary that blocks container starts to ensure they run - in order (similar to Argo Workflow's '[emissary]' executor): +#### Runtime Configuration -> The emissary works by replacing the container's command with its own command. -> This allows that command to capture stdout, the exit code, and easily -> terminate your process. The emissary can also delay the start of your process. +This design proposes Functions be long-running processes, installed by the +package manager. Deploying Functions as Kubernetes Deployments (with Services, +Service Accounts, etc) will no doubt necessitate something like a Provider's +ControllerConfig type. -You can see some of the many options Argo Workflows explored to address these -issues before landing on `emissary` in their list of -[deprecated executors][argo-deprecated-executors]. +We've identified that we [don't want to proceed][controllerconfig-deprecation] with ControllerConfig -### Using KRM Function Spec Compliant Functions -While the design proposed by this document is heavily inspired by KRM Functions, -the [KRM function specification][krm-fn-spec] as it currently exists is not an -ideal fit. This is because: +### Alternatives Considered -1. It is built around the needs of CLI tooling - including several references to - (client-side) 'files' that don't exist in the Crossplane context. -1. Crossplane needs additional metadata to distinguish which resource in the - `ResourceList` is the composite resource and which are the composed - resources. +See the [alpha design document][alpha-design]. -### gVisor -[gVisor][gvisor] supports rootless mode, but requires too many privileges to run -in a container. A proof-of-concept [exists][gvisor-unpriv] to add an -`--unprivileged` flag to gVisor, allowing it to run inside a container. It's -unlikely that gVisor will work in all situations in the near future - for -example gVisor cannot currently run inside gVisor and support for anything other -than x86 architectures is experimental. [term-composition]: https://crossplane.io/docs/v1.9/concepts/terminology.html#composition [v0.10.0]: https://github.com/crossplane/crossplane/releases/tag/v0.10.0 @@ -752,27 +986,25 @@ than x86 architectures is experimental. [declarative-app-management]: https://docs.google.com/document/d/1cLPGweVEYrVqQvBLJg6sxV-TrE5Rm2MNOBA_cxZP2WU/edit [bcl]: https://twitter.com/bgrant0607/status/1123620689930358786?lang=en [terraform-count]: https://www.terraform.io/language/meta-arguments/count -[turing-complete]: https://en.wikipedia.org/wiki/Turing_completeness#Unintentional_Turing_completeness -[pitfalls-dsl]: https://github.com/kubernetes/community/blob/8956bcd54dc6f99bcb681c79a7e5399289e15630/contributors/design-proposals/architecture/declarative-application-management.md#pitfalls-of-configuration-domain-specific-languages-dsls -[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime -[krm-fn-spec]: https://github.com/kubernetes-sigs/kustomize/blob/9d5491/cmd/config/docs/api-conventions/functions-spec.md -[rawextension]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#rawextension -[unix-domain-sockets]: https://man7.org/linux/man-pages/man7/unix.7.html -[rootless]: https://rootlesscontaine.rs/how-it-works/userns/ -[cgroups-v2-distros]: https://rootlesscontaine.rs/getting-started/common/cgroup2/#checking-whether-cgroup-v2-is-already-enabled -[overlayfs]: https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html -[go-containerregistry]: https://github.com/google/go-containerregistry -[oci-rt-cfg]: https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md -[oci-img-cfg]: https://github.com/opencontainers/image-spec/blob/v1.0.2/config.md -[gvisor-mountns]: https://github.com/google/gvisor/issues/221 -[kep-seccomp]: https://github.com/kubernetes/enhancements/issues/2413 -[package-meta]: https://github.com/crossplane/crossplane/blob/035e77b/design/one-pager-package-format-v2.md -[xpkg-spec]: https://github.com/crossplane/crossplane/blob/035e77b/docs/reference/xpkg.md -[attach]: https://github.com/kubernetes/kubectl/blob/18a531/pkg/cmd/attach/attach.go -[emissary]: https://github.com/argoproj/argo-workflows/blob/702b293/workflow/executor/emissary/emissary.go#L25 -[argo-deprecated-executors]: https://github.com/argoproj/argo-workflows/blob/v3.4.1/docs/workflow-executors.md -[krm-fn-spec]: https://github.com/kubernetes-sigs/kustomize/blob/9d5491/cmd/config/docs/api-conventions/functions-spec.md -[krm-fn-runtimes]: https://github.com/GoogleContainerTools/kpt/issues/2567 -[krm-fn-catalog]: https://catalog.kpt.dev -[gvisor]: https://gvisor.dev -[gvisor-unpriv]: https://github.com/google/gvisor/issues/4371#issuecomment-700917549 \ No newline at end of file +[alpha-design]: defunct/design-doc-composition-functions.md +[#1972]: https://github.com/crossplane/crossplane/pull/1972 +[#2352]: https://github.com/crossplane/crossplane/pull/2352 +[#4051]: https://github.com/crossplane/crossplane/pull/4051 +[#3917]: https://github.com/crossplane/crossplane/pull/3917 +[#3919]: https://github.com/crossplane/crossplane/pull/3919 +[#3989]: https://github.com/crossplane/crossplane/pull/3989 +[#3498]: https://github.com/crossplane/crossplane/pull/3498 +[#3458]: https://github.com/crossplane/crossplane/pull/3458 +[#3316]: https://github.com/crossplane/crossplane/pull/3316 +[#4036]: https://github.com/crossplane/crossplane/issues/4036 +[#4065]: https://github.com/crossplane/crossplane/issues/4065 +[#4026]: https://github.com/crossplane/crossplane/issues/4026 +[cert-per-entity]: https://github.com/crossplane/crossplane/issues/4305 +[#3884]: https://github.com/crossplane/crossplane/pull/3884 +[kubecon-eu-contribfest]: https://github.com/crossplane-contrib/contribfest/blob/main/lab-composition-functions/xfn-many/main.go +[grpc-supported-languages]: https://grpc.io/docs/languages/ +[starlark]: https://github.com/bazelbuild/starlark/blob/master/spec.md +[github-script]: https://github.com/actions/github-script +[controller-runtime-metrics]: https://book.kubebuilder.io/reference/metrics-reference.html +[event-exporter-metrics]: https://github.com/caicloud/event_exporter +[controllerconfig-deprecation]: https://github.com/crossplane/crossplane/issues/2468 \ No newline at end of file From c7a0e190a7153c5b5c29bf42e0ff61146553c787 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Mon, 10 Jul 2023 01:44:29 -0700 Subject: [PATCH 069/148] Finish the section on replacing ControllerConfig Forgot to hit save in my editor. :D Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 0083dcb95..311036fb3 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -848,7 +848,7 @@ general-purpose-esque programming language. This is similar to the ["GitHub Script"][github-script] GitHub Action that lets you plug some arbitrary logic into a GitHub Action pipeline when no existing Action does quite what you need. -### Iterating on Compositions that use Functions +#### Iterating on Compositions Getting fast feedback on a Crossplane Composition has historically been a pain because the Composition logic has been encapsulated in a Kubernetes controller. @@ -971,8 +971,11 @@ package manager. Deploying Functions as Kubernetes Deployments (with Services, Service Accounts, etc) will no doubt necessitate something like a Provider's ControllerConfig type. -We've identified that we [don't want to proceed][controllerconfig-deprecation] with ControllerConfig - +We've identified that we [don't want to proceed][controllerconfig-deprecation] +with ControllerConfig, but don't yet have a suitable alternative. Rather than +propagating a ControllerConfig-like pattern I propose we prioritize finding an +alternative. I intend to open a separate, simultaneous design to address this +since it will affect Provider packages as well as Functions. ### Alternatives Considered From 65a04f7927cdf1e1575ce6fa07e059d421900887 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Mon, 10 Jul 2023 18:58:51 -0700 Subject: [PATCH 070/148] Proof-reading pass Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 275 +++++++++++++-------- 1 file changed, 176 insertions(+), 99 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 311036fb3..c42a5063b 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -158,23 +158,19 @@ launched. The proposal put forward by this document should: * Support 'advanced' composition logic such as loops and conditionals. -* Let folks specify Composition logic in their DSL or GPL of choice. -* Make it easy to extend Crossplane with new ways to 'do Composition'. -* Decouple adding new ways do 'do Composition' from the core release cycle. +* Let folks specify composition logic in their DSL or GPL of choice. +* Make it easy to extend Crossplane with new ways to 'do composition'. +* Decouple adding new ways to 'do composition' from the core release cycle. * Be possible to keep behind a feature flag until it is generally available. -While not an explicit goal, it would also be ideal if the solution put forth by -this document could serve as a test bed - and eventually replacement for - the -contemporary "patch and transform" form of Composition. - ## Proposal This document proposes that a new `functions` array be added to the existing -`Composition` type. This array of functions would be called either instead of or +`Composition` type. This array of Functions would be called either instead of or in addition to the existing `resources` array in order to determine how an XR -should be composed. The array of functions acts as a pipeline; the output of -each function is passed as the input to the next. The output of the final -function tells Crossplane what must be done to reconcile the XR. +should be composed. The array of Functions acts as a pipeline; the output of +each Function is passed as the input to the next. The output of the final +Function tells Crossplane what must be done to reconcile the XR. ```yaml apiVersion: apiextensions.crossplane.io/v2alpha1 @@ -208,14 +204,14 @@ spec: The updated API would affect only the `Composition` type - no changes would be required to the schema of `CompositeResourceDefinitions`, XRs, etc. -Notably the functions would not need to be responsible for interacting with the +Notably the Functions would not need to be responsible for interacting with the API server to create, update, or delete composed resources. Instead, they instruct Crossplane which resources should be created, updated, or deleted. -Under the proposed design functions could also be used for purposes besides +Under the proposed design Functions could also be used for purposes besides rendering composed resources, for example validating the results of the -`resources` array or earlier functions in the `functions` array. Furthermore, a -function could also be used to implement 'side effects' such as triggering a +`resources` array or earlier Functions in the `functions` array. Furthermore, a +Function could also be used to implement 'side effects' such as triggering a replication or backup. Before you can use a Function, you must install it. Installing a Function works @@ -242,7 +238,7 @@ this proposal, Functions are long-running processes. When you install one, the package manager deploys it using a Kubernetes Deployment - the same way it would deploy a Provider. - +![Crossplane calling three Functions via gRPC](assets/design-doc-composition-functions/functions.png) Crossplane makes a gRPC `RunFunctionRequest` to the Function it wishes to invoke. The Function should respond with a `RunFunctionResponse`. These RPCs are @@ -254,14 +250,15 @@ syntax = "proto3"; import "google/protobuf/struct.proto"; import "google/protobuf/duration.proto"; -// A FunctionRunnerService runs Composition Functions. +// A FunctionRunnerService is a Composition Function. service FunctionRunnerService { - // RunFunction runs a Composition Function. + // RunFunction runs the Composition Function. rpc RunFunction(RunFunctionRequest) returns (RunFunctionResponse) {} } -// A RunFunctionRequest requests that a Composition Function be run. +// A RunFunctionRequest requests that the Composition Function be run. message RunFunctionRequest { + // Metadata pertaining to this request. RequestMeta meta = 1; // The observed state prior to invocation of a Function pipeline. State passed @@ -272,9 +269,7 @@ message RunFunctionRequest { // Desired state according to a Function pipeline. The state passed to a // particular Function may have been accumulated by processing a Composition's // patch-and-transform resources array. It may also have been accumulated by - // previous Functions in the pipeline. Functions may mutate any part of the - // desired state they are concerned with, and must pass through any part of - // the desired state that they are not concerned with. + // previous Functions in the pipeline. State desired = 3; // Configuration specific to this Function invocation. A JSON representation @@ -285,17 +280,16 @@ message RunFunctionRequest { // A RunFunctionResponse contains the result of a Composition Function run. message RunFunctionResponse { + // Metadata pertaining to this response. ResponseMeta meta = 1; - // Desired state according to a Function pipeline. The state passed to a - // particular Function may have been accumulated by previous Functions in the - // pipeline. Functions may mutate any part of the desired state they are - // concerned with, and must pass through any part of the desired state that - // they are not concerned with. + // Desired state according to a Function pipeline. Functions may add desired + // state, and may mutate or delete any part of the desired state they are + // concerned with. A Function must pass through any part of the desired state + // that it is not concerned with. State desired = 2; - // Results of the Function run. Results may be used for observability and - // debugging purposes. + // Results of the Function run. Results are used for observability purposes. repeated Result results = 3; } @@ -308,11 +302,12 @@ message RequestMeta { // ResponseMeta contains metadata pertaining to a RunFunctionResponse. message ResponseMeta { - // An opaque string identifying the content of the request. + // An opaque string identifying the content of the request. Must match the + // meta.tag of the corresponding RunFunctionRequest. string tag = 1; - // Time-to-live of this response. Idempotent functions with no side-effects - // (e.g. simple templating functions) may specify a TTL. Crossplane may choose + // Time-to-live of this response. Idempotent Functions with no side-effects + // (e.g. simple templating Functions) may specify a TTL. Crossplane may choose // to cache responses until the TTL expires. optional google.protobuf.Duration ttl = 2; } @@ -338,45 +333,47 @@ message Resource { // A Result of running a Function. message Result { // Severity of this result. - // - // Fatal results are fatal; subsequent Composition Functions may run, but - // the Composition Function pipeline run will be considered a failure and - // the first fatal result will be returned as an error. - // - // Warning results are non-fatal; the entire Composition will run to - // completion but warning events and debug logs associated with the - // composite resource will be emitted. - // - // Normal results are emitted as normal events and debug logs associated - // with the composite resource. Severity severity = 1; - // Details about the result. + // Human-readable details about the result. string message = 2; } // Severity of Function results. enum Severity { SEVERITY_UNSPECIFIED = 0; + + // Fatal results are fatal; subsequent Composition Functions may run, but + // the Composition Function pipeline run will be considered a failure and + // the first fatal result will be returned as an error. SEVERITY_FATAL = 1; + + // Warning results are non-fatal; the entire Composition will run to + // completion but warning events and debug logs associated with the + // composite resource will be emitted. SEVERITY_WARNING = 2; + + // Normal results are emitted as normal events and debug logs associated + // with the composite resource. SEVERITY_NORMAL = 3; -}; +} ``` This RPC is essentially the `RunFunctionRequest` from the [alpha Functions design][alpha-design] with the `FunctionIO` elevated from opaque YAML-encoded -bytes to 'native' RPC code. +bytes to 'native' RPC code. Kubernetes resources are represented using the +[`google.protobuf.Struct` well-known type][google-protobuf-struct], which can +encode arbitrary JSON. The package manager is responsible for creating a headless Kubernetes Service where each Function's Deployment can be reached. The address of the Service will -be exposed as the `status.endpoint` of the Function resource. The service must +be exposed as the `status.endpoint` of the Function resource. The Service must be headless in order for Crossplane's gRPC client to load-balance connections when there are multiple Function replicas. Note that the fact this endpoint is powered by a Service is an implementation detail; it may be possible for Functions to be reached (and indeed deployed) by -other means in future. +other means in future (see [Runtime Configuration][#runtime-configuration]). ```yaml apiVersion: pkg.crossplane.io/v1beta1 @@ -411,10 +408,9 @@ frequently each XR is reconciled. There are two main triggers to reconcile an XR 2. A poll-triggered reconcile, by default once per 60 seconds. XRs rely on poll-triggered reconciliation to promptly correct drift of their -composed resources. Ideally XR reconciliation would be purely watch-triggered, -but this would require dynamically adding and removing watches as the types of -resources the XR composes changes. The poll interval can be set using the -`--poll-interval` flag. +composed resources. The poll interval can be set using the `--poll-interval` +flag. The XR controller does not know what kinds of resources it will compose +when started, so it cannot start a watch for them. Assume: @@ -428,15 +424,9 @@ A few approaches are possible to scale Functions: * Tune the `--poll-interval`, e.g. to every 5m or 10m. * Scale heavily used Functions horizontally, by increasing Deployment replicas. -* Cache the responses of idempotent Function calls. - -The `RunFunctionRequest` includes a `meta.tag` field to assist with caching. The -tag identifies a unique Function input. How the tag is generated is up to the -caller (i.e. Crossplane), but two functionally identical Function inputs should -have the same tag. A Function can optionally signal that its response is valid -for the same input for a period of time by returning a non-zero `meta.ttl`. This -allows Crossplane (or an intermediary such as a reverse proxy) to cache the -responses of idempotent and side-effect-less Functions. +* Cache the responses of idempotent Function calls (see [Caching](#caching)). +* Eliminate poll-triggered XR reconciliation (see [Dynamic Composed Resource + Watches](#dynamic-composed-resource-watches)). ### Developing a Function @@ -466,7 +456,7 @@ your own" because: I propose we do three things to make Functions easy to develop: 1. Provide SDKs for popular languages - e.g. Go, Python, TypeScript. -2. Provider tooling to scaffold, build, push, and test Functions. +2. Provide tooling to scaffold, build, push, and test Functions. 3. Support providing Function logic as an OCI container that runs to completion. Consider this section a medium-resolution sketch of the Function development @@ -480,7 +470,7 @@ Consider for example the following experience for writing a Go Function. Keep in mind a similar experience would also exist for other languages. ```shell -# Initialize a new function that uses the Go SDK. +# Initialize a new Function that uses the Go SDK. $ kubectl crossplane init function --template="github.com/crossplane/fn-template-go" # This generates boilerplate that uses the Go SDK. @@ -496,7 +486,7 @@ just like a Provider or Configuration. A Function may declare dependencies - for example a Function could depend on a Provider to indicate that it composes that Provider's MRs. -After you initialize a function using the Go SDK you must update fn.go to +After you initialize a Function using the Go SDK you must update fn.go to provide your composition logic. When you first open fn.go you’ll see that `kubectl crossplane init function` added boilerplate like this: @@ -527,7 +517,7 @@ func Function(ctx context.Context, req *pb.RunFunctionRequest) (*pb.RunFunctionR } ``` -To write a function, replace the boilerplate with your own logic. Here’s an +To write a Function, replace the boilerplate with your own logic. Here’s an example that uses a mockup of a Go SDK to achieve the same goal as lab 4 from [the Kubecon EU ContribFest][kubecon-eu-contribfest]. @@ -540,8 +530,8 @@ spec: count: 5 ``` -This example takes an XR like the preceding one and uses its `spec.count` to -compose the desired number of Robot resources: +This example takes an `XRobotGroup` XR and uses its `spec.count` to compose the +desired number of Robot resources: ```go package main @@ -641,7 +631,7 @@ representations of a `RunFunctionRequest` and `RunFunctionResponse`. #### Use an OCI Container -In the [alpha iteration of Composition Functions][alpha-design] all functions +In the [alpha iteration of Composition Functions][alpha-design] all Functions are binaries that run to completion. These processes are packaged as an OCI container. A sidecar container in the Crossplane pod - `xfn` - runs each of them in a rootless container. @@ -653,13 +643,13 @@ languages that don't have a 'first class' SDK available. Think of this like AWS Lambda, which supports 9-10 first class languages, and OCI containers as a catch-all for everything else. -I propose we move the `xfn` function runner out of crossplane/crossplane, +I propose we move the `xfn` Function runner out of crossplane/crossplane, simplify it, and offer it as an alternative way to build a Function. You could think of this as a special kind of Composition Function SDK that builds a Composition Function from an OCI container, rather than building a Function a literal _function_ (e.g. written in Go). - +![Crossplane calling two containerized Functions via gRPC](assets/design-doc-composition-functions/containerized-functions.png) Under this design each containerized Function is "wrapped" in an `xfn`-like Composition Function. This means each Function exists as its own Deployment. @@ -679,14 +669,14 @@ the idea). ```Dockerfile FROM alpine:3.18 RUN apk add --no-cache jq -ENTRYPOINT ["/bin/sh", "-c", "jq '(.desired.resources[] | .resource.metadata.labels) |= {\"labelizer.xfn.crossplane.io/processed\": \"true\"} + .' | .desired.resources"] +ENTRYPOINT ["/bin/sh", "-c", "jq '(.desired.resources[] | .resource.metadata.labels) |= {\"labelizer.xfn.crossplane.io/processed\": \"true\"} + .' | .desired"] ``` Then build a Function from the image. We want the image to run in its own -container, nested inside the Function container. This allows the OCI container -to run within its own namespaces without interfering with (or being interfered -with by) the `xfn`-like 'adaptor'. To do this we bake the container into the -Function artifact: +container, not the Function container. This allows the OCI container to run +within its own namespaces without interfering with (or being interfered with by) +the `xfn`-like 'adaptor'. To do this we bake the container into the Function +artifact: ```shell # Build your OCI image. @@ -725,7 +715,8 @@ lot. However the general pattern is: 1. Find (or build!) a Function you want to use. 2. Install the Function using the package manager. -3. Include the Function (and any Function config) in a Composition. +3. Reference the Function in a Composition. +4. Provide Function configuration in the Composition, where necessary. Again, consider this section a medium-resolution sketch of the Function experience. The generic Functions demonstrates here don't actually exist (yet!). @@ -733,7 +724,7 @@ They may not look exactly as proposed here. This section intends only to paint a picture of what Functions enable. Consider the hypothetical generic "Go templates" Function put forward at the -[beginning of this proposal][#proposal]. Such a Function would make it possible +[beginning of this proposal](#proposal). Such a Function would make it possible to write a Composition that used familiar, Helm-like moustache templates with support for iteration and conditionals. @@ -777,10 +768,9 @@ spec: {{- end }} ``` -This example is functionally identical to [the Go example][#use-language-sdks], +This example is functionally identical to [the Go example](#use-language-sdks), but uses a DSL - Go templates with http://masterminds.github.io/sprig/ and a -few Crossplane-specific functions. Indeed this Function could be built using the -Go SDK - a generic Function for anyone who prefers Go Templates. +few Crossplane-specific Functions. Here's another example of a generic Function. This one lets Composition authors express their Composition logic in arbitrary, inline [Starlark][starlark]. @@ -805,7 +795,7 @@ spec: # main is passed a RunFunctionRequest as a (Python-like) dictionary. # It must return a RunFunctionResponse-shaped dictionary. def main(req): - rsp = {desired=req["desired"], results=req["results]} + rsp = {desired=req["desired"]} xr = req["observed"]["composite"]["resource"] for i in range(int(xr["spec"]["count"])): @@ -841,12 +831,13 @@ spec: return rsp ``` -Starlark is a (very) limited dialect of Python designed configuration. It embeds -into many languages - including Go. This makes it a great candidate to build a -generic Function that allows Composition authors to provide _inline_ logic in a -general-purpose-esque programming language. This is similar to the ["GitHub -Script"][github-script] GitHub Action that lets you plug some arbitrary logic -into a GitHub Action pipeline when no existing Action does quite what you need. +Starlark is a (very) limited dialect of Python designed for configuration. It +embeds into many languages, including Go. This makes it a great candidate to +build a generic Function that allows Composition authors to provide _inline_ +logic in a general-purpose-ish programming language. This is similar to the +["GitHub Script"][github-script] GitHub Action that lets you plug some arbitrary +logic into a GitHub Action pipeline when no existing Action does quite what you +need. #### Iterating on Compositions @@ -862,11 +853,11 @@ In order to know whether your Composition works as intended you need to: Moving Composition logic out of Crossplane and into versioned Functions makes it a lot easier to test and iterate on, client-side. For example a `function test` -command could test a single function in isolation: +command could test a single Function in isolation: ```shell # Test a single Function by passing it a JSON RunFunctionRequest. This pulls and -# starts the function, makes the request, stops it, then returns the result. +# starts the Function, makes the request, stops it, then returns the result. $ kubectl crossplane function test xpkg.upbound.io/negz/go-templates:v0.1.0 run-function-request.json { # JSON encoded RunFunctionResponse omitted for brevity. @@ -901,14 +892,14 @@ like `helm template`. The advantage of Functions in this regard is that the `composition render` command would need to duplicate much less code from the Crossplane Composition -controller than if it were to try to recreate the built-in P&T logic. +controller than if it were to try to recreate Crossplane's hardcoded P&T logic. -### Future Improvements +## Future Improvements The following functionality is out-of-scope for the beta implementation, but may be added in future. -#### Function Config Custom Resources +### Function Config Custom Resources In the current alpha implementation of Functions, and this design, Function configuration is a custom-resource-like inline resource (i.e. an @@ -928,7 +919,7 @@ configuration is a custom-resource-like inline resource (i.e. an In future it may be useful for a Function to be able to deliver this type as a custom resource definition (CRD). This would allow a single configuration to be more easily shared by multiple Compositions. A Composition could reference a -Function configuration: +Function configuration custom resource: ```yaml functions: @@ -944,7 +935,7 @@ Function configuration: At this stage I suggest holding off on building this functionality until there is clear demand. -#### Metrics and Tracing +### Metrics and Tracing Crossplane does not currently expose its own metrics. It relies on [the set it gets from controller-runtime][controller-runtime-metrics], and metrics that @@ -959,12 +950,44 @@ order to debug slow or failing Functions in a pipeline. Metrics and tracing for Functions must be implemented before the feature becomes generally available (GA). -#### Caching +### Caching + +The API proposed by this design accommodates caching. The `RunFunctionRequest` +includes a `meta.tag` field. The tag identifies a unique Function input. How the +tag is generated is up to the caller (i.e. Crossplane), but two functionally +identical Function inputs should have the same tag. A Function can optionally +signal that its response is valid for the same input for a period of time by +returning a non-zero `meta.ttl`. This allows Crossplane (or an intermediary such +as a reverse proxy) to cache the responses of idempotent and side-effect-less +Functions. + +Building caching support is not in scope for beta. This will likely prove to be +a requirement for GA. -The gRPC API proposed by this design accomodates caching, but building caching -support is not in scope for beta. This will likely be a requirement for GA. +### Dynamic Composed Resource Watches -#### Runtime Configuration +Ideally XR reconciliation would be purely watch-triggered - this would result in +less work for the XR controller, and far fewer Function calls. + +The XR controller currently watches the XR type, but is also poll-triggered, by +default polling desired state every 60 seconds. This interval can be changed by +the `--poll-interval` flag. The XR reconciler is poll-triggered because it wants +to know when composed resources change, in order to correct drift. + +An XR controller doesn't know what kinds of resources it will compose at start +time, which is typically when a controller's watches are configured. +Furthermore, two different XRs of the same kind might compose completely +different types of resources due to using different Compositions. + +This is something we should revisit regardless of Functions. For example it may +be possible to: + +1. Make one controller responsible (only) for selecting a Composition for an XR. +2. Start another controller for every unique (XR, Composition) tuple. +3. Restart the (XR, Composition) controller whenever the XR's + `spec.resourceRefs` changes, watching all referenced types. + +### Runtime Configuration This design proposes Functions be long-running processes, installed by the package manager. Deploying Functions as Kubernetes Deployments (with Services, @@ -977,7 +1000,60 @@ propagating a ControllerConfig-like pattern I propose we prioritize finding an alternative. I intend to open a separate, simultaneous design to address this since it will affect Provider packages as well as Functions. -### Alternatives Considered +### Patch-and-Transform as a Function + +A key benefit of Functions is that composition logic is decoupled from the core +Crossplane release cycle. Moving composition logic out-of-tree and versioning it +separately from Crossplane allows us to iterate faster, and experiment more +freely. + +P&T style Composition could enjoy these benefits if it were not a special case, +and were just another Function. Imagine for example wanting a new type of patch +or a new type of transform and being able to simply fork the implementation to +experiment without affecting everyone who uses Crossplane. + +P&T Composition as a Function might look like this: + +```yaml +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: example +spec: + compositeTypeRef: + apiVersion: database.example.org/v1alpha1 + kind: AcmeCoDatabase + functions: + - name: patch-and-transform + functionRef: + name: patch-and-transform + config: + apiVersion: apiextensions.crossplane.io/v1 + kind: Resources + resources: + - name: cloudsqlinstance + base: + apiVersion: database.gcp.crossplane.io/v1beta1 + kind: CloudSQLInstance + spec: + forProvider: + databaseVersion: POSTGRES_9_6 + region: us-central1 + settings: + tier: db-custom-1-3840 + dataDiskType: PD_SSD + patches: + - type: FromCompositeFieldPath + fromFieldPath: spec.parameters.storageGB + toFieldPath: spec.forProvider.settings.dataDiskSizeGb +``` + +Removing P&T support from the Composition type would be a breaking API change - +not something we could do easily. One approach could be to deprecate and +'freeze' the API, recommending folks who prefer P&T style use the generic P&T +Function instead. + +## Alternatives Considered See the [alpha design document][alpha-design]. @@ -1002,6 +1078,7 @@ See the [alpha design document][alpha-design]. [#4036]: https://github.com/crossplane/crossplane/issues/4036 [#4065]: https://github.com/crossplane/crossplane/issues/4065 [#4026]: https://github.com/crossplane/crossplane/issues/4026 +[google-protobuf-struct]: https://protobuf.dev/reference/protobuf/google.protobuf/#struct [cert-per-entity]: https://github.com/crossplane/crossplane/issues/4305 [#3884]: https://github.com/crossplane/crossplane/pull/3884 [kubecon-eu-contribfest]: https://github.com/crossplane-contrib/contribfest/blob/main/lab-composition-functions/xfn-many/main.go From 0688b6d0c995c8b0d9a9724bf1c9c747f7db05f4 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 15:48:48 -0700 Subject: [PATCH 071/148] Address typos caught during review Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index c42a5063b..9b72f1831 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -150,7 +150,7 @@ In the time since P&T Composition became available we've seen that: To address these issues, we added support for 'Composition Functions' in Crossplane v1.11. Functions are an alpha feature and are off by default. This document is an iteration on (and supersedes) the [previous design -document][alpha-design] based on what we've learned during since the feature was +document][alpha-design] based on what we've learned since the feature was launched. ## Goals @@ -190,7 +190,7 @@ spec: # The functionRef tells the Composition which Function to use. This Function # uses Go Templates (like Helm) to render composed resources. functionRef: - - name: go-templates + name: go-templates # A Function may optionally accept configuration. The configuration is # passed to the Function when it is called. The configuration block looks # like a nested custom resource - i.e. it has an apiVersion and kind. @@ -373,7 +373,7 @@ when there are multiple Function replicas. Note that the fact this endpoint is powered by a Service is an implementation detail; it may be possible for Functions to be reached (and indeed deployed) by -other means in future (see [Runtime Configuration][#runtime-configuration]). +other means in future (see [Runtime Configuration](#runtime-configuration)). ```yaml apiVersion: pkg.crossplane.io/v1beta1 From f3c6f7459f22ccd5dc4e30748565dcd01200a20d Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 16:50:46 -0700 Subject: [PATCH 072/148] Expand on the motivation for this new design Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 9b72f1831..f7fcf2bf5 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -148,10 +148,29 @@ In the time since P&T Composition became available we've seen that: particular configuration DSL, others look for webhooks written in a GPL, etc. To address these issues, we added support for 'Composition Functions' in -Crossplane v1.11. Functions are an alpha feature and are off by default. This -document is an iteration on (and supersedes) the [previous design +Crossplane v1.11. Functions are an alpha feature and are off by default. In the +[alpha design][alpha-design] we proposed that how a Function was implemented +could vary in at least two ways: + +* By `type` - i.e. `type: Container`, `type: Webhook`. +* By "runner" implementation - i.e. how a `type: Container` Function is run. + +We implemented a "default" or "reference" `type: Container` Function runner with +known scalability and compatibility constraints, but didn't lay out a clear path +for others to build alternative Function runners. Since alpha, no alternative +Function runners have appeared. + +The aforementioned limitations of the reference Function runner lead to a demand +to support webhook Functions as an alternative. Ultimately we were reluctant to +support this because it fragments the Function ecosystem. When a Function can be +an OCI container or a webhook (or more in future?) there is no one artifact that +constitutes "a Function". This makes discovery and distribution of Functions +more complicated than we would like. + +This document is an iteration on (and supersedes) the [previous design document][alpha-design] based on what we've learned since the feature was -launched. +launched. In particular, it is motivated by the desire to identify a single kind +of Function artifact suitable for most people - similar to Providers. ## Goals @@ -161,6 +180,7 @@ The proposal put forward by this document should: * Let folks specify composition logic in their DSL or GPL of choice. * Make it easy to extend Crossplane with new ways to 'do composition'. * Decouple adding new ways to 'do composition' from the core release cycle. +* Make it easy to discover and share new ways to 'do composition'. * Be possible to keep behind a feature flag until it is generally available. ## Proposal From 1380d342f65a30ce3b1911dce8cd11a87f8c1f8c Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 17:23:12 -0700 Subject: [PATCH 073/148] Rename 'functions' and 'name' to 'pipeline' and 'step' This reduces the amount of times 'name' appears and clarifies that the Functions array is a pipeline of functions. Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 66 ++++++++++++---------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index f7fcf2bf5..064384ad8 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -185,12 +185,13 @@ The proposal put forward by this document should: ## Proposal -This document proposes that a new `functions` array be added to the existing -`Composition` type. This array of Functions would be called either instead of or -in addition to the existing `resources` array in order to determine how an XR -should be composed. The array of Functions acts as a pipeline; the output of -each Function is passed as the input to the next. The output of the final -Function tells Crossplane what must be done to reconcile the XR. +This document proposes that a new `pipeline` array of Function calls be added to +the existing `Composition` type. This array of Functions would be called either +instead of or in addition to the existing `resources` array in order to +determine how an XR should be composed. The array of Functions acts as a +pipeline; the output of each Function is passed as the input to the next. The +output of the final Function call tells Crossplane what must be done to +reconcile the XR. ```yaml apiVersion: apiextensions.crossplane.io/v2alpha1 @@ -201,24 +202,28 @@ spec: compositeTypeRef: apiVersion: database.example.org/v1 kind: XPostgreSQLInstance - # This Composition specifies functions instead of (P&T) resources. - # This is an array - you can specify a pipeline of Functions. - functions: - # Each entry in the functions array has a name. This uniquely identifies - # the Function 'call' within the Composition. - - name: compose-xr-using-go-templates - # The functionRef tells the Composition which Function to use. This Function - # uses Go Templates (like Helm) to render composed resources. + # This Composition uses a pipeline of Functions instead of (P&T) resources. + pipeline: + # Each step in the pipeline calls one Composition Function. + - step: compose-xr-using-go-templates + # The functionRef tells the Composition which Function to call. Crossplane + # passes the desired and observed state of the XR and any existing composed + # resources as 'arguments' to the Function call. functionRef: name: go-templates - # A Function may optionally accept configuration. The configuration is - # passed to the Function when it is called. The configuration block looks - # like a nested custom resource - i.e. it has an apiVersion and kind. + # A Function call may optionally accept configuration. Think of this like an + # additional, optional argument to the Function call. The configuration is a + # nested KRM resource - i.e. it has an apiVersion and kind. config: apiVersion: example.org/v1 kind: GoTemplate source: Remote remote: git://github.com/example/my-xpostgresql-go-templates + # A pipeline can have multiple steps. Each step is processed in order. This + # validation step is passed the desired state accumulated by the prior step. + - step: validate-composed-resources + functionRef: + name: cel-validation ``` The updated API would affect only the `Composition` type - no changes would be @@ -230,7 +235,7 @@ instruct Crossplane which resources should be created, updated, or deleted. Under the proposed design Functions could also be used for purposes besides rendering composed resources, for example validating the results of the -`resources` array or earlier Functions in the `functions` array. Furthermore, a +`resources` array or earlier Functions in the `pipeline`. Furthermore, a Function could also be used to implement 'side effects' such as triggering a replication or backup. @@ -293,8 +298,7 @@ message RunFunctionRequest { State desired = 3; // Configuration specific to this Function invocation. A JSON representation - // of the 'config' block of the relevant entry in a Composition's 'functions' - // array. + // of the 'config' block of the relevant entry in a Composition's pipeline. optional google.protobuf.Struct config = 4; } @@ -760,8 +764,8 @@ spec: compositeTypeRef: apiVersion: database.example.org/v1 kind: XPostgreSQLInstance - functions: - - name: compose-xr-using-go-templates + pipeline: + - step: compose-xr-using-go-templates functionRef: name: go-templates config: @@ -804,8 +808,8 @@ spec: compositeTypeRef: apiVersion: database.example.org/v1 kind: XPostgreSQLInstance - functions: - - name: compose-xr-using-go-templates + pipeline: + - step: compose-xr-using-go-templates functionRef: name: starlark config: @@ -896,7 +900,7 @@ $ kubectl crossplane composition render composition.yaml xr.yaml Assuming a 'pure' Composition consisting only of Functions with no P&T resources, this command would need only to iterate through the Composition's -`functions` array, and for each Function: +`pipeline`, and for each Function: 1. Pull and start it. 2. Form a `RunFunctionRequest` from the XR and any prior `RunFunctionResponse`. @@ -926,8 +930,8 @@ configuration is a custom-resource-like inline resource (i.e. an `x-kubernetes-embedded-resource`): ```yaml - functions: - - name: compose-xr-using-go-templates + pipeline: + - step: compose-xr-using-go-templates functionRef: name: starlark config: @@ -942,8 +946,8 @@ more easily shared by multiple Compositions. A Composition could reference a Function configuration custom resource: ```yaml - functions: - - name: compose-xr-using-go-templates + pipeline: + - step: compose-xr-using-go-templates functionRef: name: starlark configRef: @@ -1043,8 +1047,8 @@ spec: compositeTypeRef: apiVersion: database.example.org/v1alpha1 kind: AcmeCoDatabase - functions: - - name: patch-and-transform + pipeline: + - step: patch-and-transform functionRef: name: patch-and-transform config: From a69f6bfc0f27a25901eed54626522f35df3a51ee Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 18:45:39 -0700 Subject: [PATCH 074/148] Elaborate on predicted Function performance Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 064384ad8..c895b55f6 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -444,13 +444,24 @@ Assume: In this case the Function would be called __100 * 1 = 100 times per 60s__. -A few approaches are possible to scale Functions: - -* Tune the `--poll-interval`, e.g. to every 5m or 10m. +Most gRPC server implementations can serve multiple requests concurrently. For +example in Go [each RPC is invoked in its own goroutine][go-grpc-concurrency]. +The gRPC project maintains a [suite of benchmarks][grpc-benchmarks]. At the time +of writing these benchmarks show that an 8-core Python server can serve ~3,500 +trivial requests per second, while an 8-core Go server can serve ~180,000 per +second. This should be considered a ceiling rather than indicative of real-world +Function performance. In practice the throughput of a particular Function will +be determined by the language it's written in, and what it does. + +Inevitably some Functions will be called frequently enough to exhaust the +processing capacity of a single pod. A few potential approaches are possible to +scale Functions include: + +* Tune the `--poll-interval`, e.g. to every 5m or 10m, to reduce calls. * Scale heavily used Functions horizontally, by increasing Deployment replicas. * Cache the responses of idempotent Function calls (see [Caching](#caching)). -* Eliminate poll-triggered XR reconciliation (see [Dynamic Composed Resource - Watches](#dynamic-composed-resource-watches)). +* Eliminate poll-triggered XR reconciliation to reduce calls (see [Dynamic + Composed Resource Watches](#dynamic-composed-resource-watches)). ### Developing a Function @@ -1105,6 +1116,8 @@ See the [alpha design document][alpha-design]. [google-protobuf-struct]: https://protobuf.dev/reference/protobuf/google.protobuf/#struct [cert-per-entity]: https://github.com/crossplane/crossplane/issues/4305 [#3884]: https://github.com/crossplane/crossplane/pull/3884 +[go-grpc-concurrency]: https://github.com/grpc/grpc-go/blob/master/Documentation/concurrency.md#servers +[grpc-benchmarks]: https://grpc.io/docs/guides/benchmarking/ [kubecon-eu-contribfest]: https://github.com/crossplane-contrib/contribfest/blob/main/lab-composition-functions/xfn-many/main.go [grpc-supported-languages]: https://grpc.io/docs/languages/ [starlark]: https://github.com/bazelbuild/starlark/blob/master/spec.md From e320174016a57c8351f74e5a7987d1f7218ceb16 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 18:47:42 -0700 Subject: [PATCH 075/148] Clarify goals of Function SDKs i.e. Be explicit that we want to asbtract away the fact that these are servers. Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index c895b55f6..dc72caf96 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -633,9 +633,9 @@ func Function(ctx context.Context, req *pb.RunFunctionRequest) (*pb.RunFunctionR The goals of a Composition Function SDK are to: +* Eliminate boilerplate - make it feel like writing a function, not a server. * Expose an API that makes writing Functions intuitive and self-documenting. * Steer Function authors toward best practices, and away from anti-patterns. -* Eliminate boilerplate, like setting up a gRPC server. This mockup only touches on very basic functionality. A fully featured SDK would cover more use cases - for example reading Function-specific config and working From b654f8dc63bf38898fc8a16f9c41f514caf61211 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 19:02:11 -0700 Subject: [PATCH 076/148] Highlight key differences from FunctionIO Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index dc72caf96..9d74b03d2 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -384,10 +384,23 @@ enum Severity { ``` This RPC is essentially the `RunFunctionRequest` from the [alpha Functions -design][alpha-design] with the `FunctionIO` elevated from opaque YAML-encoded -bytes to 'native' RPC code. Kubernetes resources are represented using the -[`google.protobuf.Struct` well-known type][google-protobuf-struct], which can -encode arbitrary JSON. +design][alpha-design] with the [`FunctionIO`][functionio-schema] elevated from +opaque YAML-encoded bytes to 'native' RPC code. Kubernetes resources are +represented using the [`google.protobuf.Struct` well-known +type][google-protobuf-struct], which can encode arbitrary JSON. + +Some key differences between the alpha `FunctionIO` and the proposed beta +`RunFunctionRequest`: + +* `observed.resources` and `desired.resources` are a map keyed by resource name, + not an array of objects with name fields. The previous pattern was a result of + `FunctionIO` attempting to be an idiomatic KRM object, which is not a + constraint for `RunFunctionRequest`. This is should make it easier to lookup + resources by name when developing Functions. +* Entries in `desired.resources` can no longer return 'derived' connection + secrets or readiness checks, similar to an entry in the P&T resources array. + Instead a Function is intended to set XR connection details and/or readiness + by mutating them directly. The package manager is responsible for creating a headless Kubernetes Service where each Function's Deployment can be reached. The address of the Service will @@ -1118,6 +1131,7 @@ See the [alpha design document][alpha-design]. [#3884]: https://github.com/crossplane/crossplane/pull/3884 [go-grpc-concurrency]: https://github.com/grpc/grpc-go/blob/master/Documentation/concurrency.md#servers [grpc-benchmarks]: https://grpc.io/docs/guides/benchmarking/ +[functionio-schema]: https://github.com/crossplane/crossplane/blob/v1.12.2/apis/apiextensions/fn/io/v1alpha1/functionio_types.go#L28 [kubecon-eu-contribfest]: https://github.com/crossplane-contrib/contribfest/blob/main/lab-composition-functions/xfn-many/main.go [grpc-supported-languages]: https://grpc.io/docs/languages/ [starlark]: https://github.com/bazelbuild/starlark/blob/master/spec.md From 746461889df23495bf00e8c6be4d0023ca185fa0 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 19:08:29 -0700 Subject: [PATCH 077/148] Add 'Installing a Function' section This was mostly covered already, but now easier to find and with a touch more detail (e.g. on dependencies). Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 9d74b03d2..9ca7d85e5 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -756,6 +756,21 @@ Note that most of this functionality already exists in `xfn`. This makes it cheap enough to implement this Function variant that I believe it's worth doing, even if it ends up covering a relatively niche case. +### Installing a Function + +Before you can use a Function, you must install it. Installing a Function works +just like installing a Provider: + +```yaml +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: go-templates +spec: + package: xpkg.upbound.io/negz/go-templates:v0.1.0 +``` + + ### Using a Function Composition Functions are very flexible, so the user experience could vary a From 1ec01190b9be12c86e7e67a73a2b982a45c2f94a Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 11 Jul 2023 19:28:16 -0700 Subject: [PATCH 078/148] Note that we could simulate observed resources This could be useful when running 'composition render'. Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 9ca7d85e5..2af52f40d 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -253,8 +253,7 @@ spec: The Function package's `metadata.name` corresponds to the `functionRef` in the previous example Composition. A Composition specifies which Function to run by -referencing the package's name. Like any other package, the `Function` type will -have a corresponding `FunctionRevision` type. +referencing the package's name. ### Calling a Function @@ -770,8 +769,16 @@ spec: package: xpkg.upbound.io/negz/go-templates:v0.1.0 ``` +Like any other package, the Function type will have a corresponding +FunctionRevision type. The package manager will reconcile the active revision by +creating a Deployment - similar to how it installs a Provider. -### Using a Function +Functions can have and be dependencies, just like a Provider or Configuration. +For example a Configuration could depend on the Functions its Compositions use, +and a Function could depend on the Providers and Configurations whose resources +it will compose. + +### Calling a Function Composition Functions are very flexible, so the user experience could vary a lot. However the general pattern is: @@ -947,7 +954,8 @@ resources, this command would need only to iterate through the Composition's This isn't quite an end-to-end test of Composition. The composed resources are not actually created and reconciled with an external system, so its not possible -for example to derive XR status from composed resource status. It's also not +for example to derive XR status from composed resource status. (Though that +could perhaps be simulated by providing fake observed resources.) It's also not possible in isolation to determine whether the rendered composed resources are schematically valid. It does however give you a good idea of whether your Composition will produce the set of composed resources that you'd expect - just From 8525caf3c83091c9982488b7dcb36ff83159f88f Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Wed, 12 Jul 2023 10:49:54 -0700 Subject: [PATCH 079/148] Remove mention of Function side-effects This was thrown in during the original design while we toyed with Functions as being a way to do "day two stuff" (e.g. trigger backups). I don't think anyone is confident that this is a good idea, so let's not mention it for now. Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 2af52f40d..f972fccaa 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -232,12 +232,9 @@ required to the schema of `CompositeResourceDefinitions`, XRs, etc. Notably the Functions would not need to be responsible for interacting with the API server to create, update, or delete composed resources. Instead, they instruct Crossplane which resources should be created, updated, or deleted. - Under the proposed design Functions could also be used for purposes besides rendering composed resources, for example validating the results of the -`resources` array or earlier Functions in the `pipeline`. Furthermore, a -Function could also be used to implement 'side effects' such as triggering a -replication or backup. +`resources` array or earlier Functions in the `pipeline`. Before you can use a Function, you must install it. Installing a Function works just like installing a Provider: From 6fd80fdff4e0fedbe04ed0e20ab3fbc04d4f29c8 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Wed, 12 Jul 2023 10:54:47 -0700 Subject: [PATCH 080/148] Note explicitly that there is no watch on Composition Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index f972fccaa..8fda441d2 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -445,6 +445,12 @@ composed resources. The poll interval can be set using the `--poll-interval` flag. The XR controller does not know what kinds of resources it will compose when started, so it cannot start a watch for them. +Note that there is no watch on the Composition type. XRs consume a Composition +via a CompositionRevision. Each time the Composition changes a new revision is +created. The XR is pinned to a specific revision of a Composition until it is +updated to consume a new one. This update would trigger a reconcile due to the +watch on the XR. + Assume: * There are 100 XRs, all of the same type, and all using the same Composition. From 49cb1e5881027e24a76fe5c366ddf36b5ec07c9c Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Wed, 12 Jul 2023 11:04:53 -0700 Subject: [PATCH 081/148] s/idempotent/deterministic/ Mixing up my CS terms. :) Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index 8fda441d2..bc7bc81ca 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -326,7 +326,7 @@ message ResponseMeta { // meta.tag of the corresponding RunFunctionRequest. string tag = 1; - // Time-to-live of this response. Idempotent Functions with no side-effects + // Time-to-live of this response. Deterministic Functions with no side-effects // (e.g. simple templating Functions) may specify a TTL. Crossplane may choose // to cache responses until the TTL expires. optional google.protobuf.Duration ttl = 2; @@ -474,7 +474,7 @@ scale Functions include: * Tune the `--poll-interval`, e.g. to every 5m or 10m, to reduce calls. * Scale heavily used Functions horizontally, by increasing Deployment replicas. -* Cache the responses of idempotent Function calls (see [Caching](#caching)). +* Cache the responses of deterministic Function calls (see [Caching](#caching)). * Eliminate poll-triggered XR reconciliation to reduce calls (see [Dynamic Composed Resource Watches](#dynamic-composed-resource-watches)). @@ -1032,7 +1032,7 @@ tag is generated is up to the caller (i.e. Crossplane), but two functionally identical Function inputs should have the same tag. A Function can optionally signal that its response is valid for the same input for a period of time by returning a non-zero `meta.ttl`. This allows Crossplane (or an intermediary such -as a reverse proxy) to cache the responses of idempotent and side-effect-less +as a reverse proxy) to cache the responses of deterministic and side-effect-less Functions. Building caching support is not in scope for beta. This will likely prove to be From aa8bd83195ff7505a9c4ed9126f161673a0ec55a Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Thu, 13 Jul 2023 13:51:53 -0700 Subject: [PATCH 082/148] Rename function 'config' to 'input' This better frames it as what is is - input to a particular Function call. The downside with calling if 'config' was that folks could mistake it to mean it was configuring the Function _globally_, not just configuring how one particular entry in one Composition's pipeline of steps calls a Function. Signed-off-by: Nic Cope --- design/design-doc-composition-functions.md | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/design/design-doc-composition-functions.md b/design/design-doc-composition-functions.md index bc7bc81ca..e6a84e6ce 100644 --- a/design/design-doc-composition-functions.md +++ b/design/design-doc-composition-functions.md @@ -211,10 +211,10 @@ spec: # resources as 'arguments' to the Function call. functionRef: name: go-templates - # A Function call may optionally accept configuration. Think of this like an - # additional, optional argument to the Function call. The configuration is a - # nested KRM resource - i.e. it has an apiVersion and kind. - config: + # A Function call may optionally accept input. Think of this like an + # additional, optional argument to the Function call. The input is a nested + # KRM resource - i.e. it has an apiVersion and kind. + input: apiVersion: example.org/v1 kind: GoTemplate source: Remote @@ -293,9 +293,9 @@ message RunFunctionRequest { // previous Functions in the pipeline. State desired = 3; - // Configuration specific to this Function invocation. A JSON representation - // of the 'config' block of the relevant entry in a Composition's pipeline. - optional google.protobuf.Struct config = 4; + // Optional input specific to this Function invocation. A JSON representation + // of the 'input' block of the relevant entry in a Composition's pipeline. + optional google.protobuf.Struct input = 4; } // A RunFunctionResponse contains the result of a Composition Function run. @@ -653,7 +653,7 @@ The goals of a Composition Function SDK are to: * Steer Function authors toward best practices, and away from anti-patterns. This mockup only touches on very basic functionality. A fully featured SDK would -cover more use cases - for example reading Function-specific config and working +cover more use cases - for example reading Function-specific input and working with connection details. Once you’ve written your Function code you can test it using the tooling for @@ -789,7 +789,7 @@ lot. However the general pattern is: 1. Find (or build!) a Function you want to use. 2. Install the Function using the package manager. 3. Reference the Function in a Composition. -4. Provide Function configuration in the Composition, where necessary. +4. Provide Function input in the Composition, where necessary. Again, consider this section a medium-resolution sketch of the Function experience. The generic Functions demonstrates here don't actually exist (yet!). @@ -817,7 +817,7 @@ spec: - step: compose-xr-using-go-templates functionRef: name: go-templates - config: + input: apiVersion: example.org/v1 kind: GoTemplate source: Inline # Or Remote, if you want to pull templates from git. @@ -861,7 +861,7 @@ spec: - step: compose-xr-using-go-templates functionRef: name: starlark - config: + input: apiVersion: example.org/v1 kind: StarlarkScript script: | @@ -973,10 +973,10 @@ controller than if it were to try to recreate Crossplane's hardcoded P&T logic. The following functionality is out-of-scope for the beta implementation, but may be added in future. -### Function Config Custom Resources +### Function Input Custom Resources In the current alpha implementation of Functions, and this design, Function -configuration is a custom-resource-like inline resource (i.e. an +input is a custom-resource-like inline resource (i.e. an `x-kubernetes-embedded-resource`): ```yaml @@ -984,23 +984,23 @@ configuration is a custom-resource-like inline resource (i.e. an - step: compose-xr-using-go-templates functionRef: name: starlark - config: + input: apiVersion: example.org/v1 kind: StarlarkScript script: ... ``` In future it may be useful for a Function to be able to deliver this type as a -custom resource definition (CRD). This would allow a single configuration to be -more easily shared by multiple Compositions. A Composition could reference a -Function configuration custom resource: +custom resource definition (CRD). This would allow a single input to be more +easily shared by multiple Compositions. A Composition could reference a Function +input custom resource: ```yaml pipeline: - step: compose-xr-using-go-templates functionRef: name: starlark - configRef: + inputRef: apiVersion: example.org/v1 kind: StarlarkScript name: make-some-purple-robots @@ -1101,7 +1101,7 @@ spec: - step: patch-and-transform functionRef: name: patch-and-transform - config: + input: apiVersion: apiextensions.crossplane.io/v1 kind: Resources resources: From 4a0bb29431cdfdb299fb6605aec10a50e2561145 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 11 Jul 2023 17:00:40 +0200 Subject: [PATCH 083/148] xrd/claim: event triggered composite update event Signed-off-by: Dr. Stefan Schimanski --- .../controller/apiextensions/claim/reconciler.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/controller/apiextensions/claim/reconciler.go b/internal/controller/apiextensions/claim/reconciler.go index 2bd01d049..ca549764c 100644 --- a/internal/controller/apiextensions/claim/reconciler.go +++ b/internal/controller/apiextensions/claim/reconciler.go @@ -25,6 +25,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -520,17 +521,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, cm), errUpdateClaimStatus) } - if err := r.client.Apply(ctx, cp); err != nil { + err := r.client.Apply(ctx, cp, resource.AllowUpdateIf(func(old, obj runtime.Object) bool { return !cmp.Equal(old, obj) })) + switch { + case resource.IsNotAllowed(err): + log.Debug("Skipped no-op composite resource apply") + case err != nil: log.Debug(errApplyComposite, "error", err) err = errors.Wrap(err, errApplyComposite) record.Event(cm, event.Warning(reasonCompositeConfigure, err)) cm.SetConditions(xpv1.ReconcileError(err)) return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, cm), errUpdateClaimStatus) + default: + log.Debug("Successfully applied composite resource") + record.Event(cm, event.Normal(reasonCompositeConfigure, "Successfully applied composite resource")) } - log.Debug("Successfully applied composite resource") - record.Event(cm, event.Normal(reasonCompositeConfigure, "Successfully applied composite resource")) - if err := r.claim.Configure(ctx, cm, cp); err != nil { log.Debug(errConfigureClaim, "error", err) err = errors.Wrap(err, errConfigureClaim) From 825f0840b798b3b0d69949fc0be473be90813e93 Mon Sep 17 00:00:00 2001 From: Hasan Turken Date: Fri, 14 Jul 2023 14:52:56 +0300 Subject: [PATCH 084/148] Update usage design per feedback Signed-off-by: Hasan Turken --- design/images/usage-owner-ref.png | Bin 0 -> 47712 bytes design/one-pager-generic-usage-type.md | 123 +++++++++++++++++++------ 2 files changed, 93 insertions(+), 30 deletions(-) create mode 100644 design/images/usage-owner-ref.png diff --git a/design/images/usage-owner-ref.png b/design/images/usage-owner-ref.png new file mode 100644 index 0000000000000000000000000000000000000000..14d2be2e329ef293aa2fe272ade62e6e72fc82a1 GIT binary patch literal 47712 zcmZtuc_7qX|38k8rL>4#CCYZSQL?rWLM7A{O7?X`vYX4^U}mVRREkO=vXmmm8fLQ2 zw1^sOvJOTvmKp0XW{jEfJukYi`+k3Zzy2t3=Dg19d7kIFJRXnZ-en8ZZCmzifx%$g zE}TDi1qR#5g~0?fH*Eyp@u{nIhQVTB7tWorzTrAG*oQq%tR(XUC$wEU>d-jSES&l~>Oe7tgq2@2rqnE~{_>@Nn=)w0kuLvHm6Oj?u8l z`j(3@yI3AtLLGT$V1b?U1 z@l|ftZF&}eGAq20-?Per?>K^=_MozYpMT4m+_wQ%x}CBN>=830!7e&2=J+Z&#;Qbi zXV(!Cm%paZQ7I&(@@hT8ZW-Z~4Bi`zGv7By{t~{|MZc-(<=rd3Jmt8QnvMrU;hdi>XUsPSdyvy1YgL{7I4>y;-k3ulw zh?d$MHf|?rqtHCt*TDuRD0)#$qh^yBHsE%E@Y=*Ky?2QvTd2WGT$O`AglI3_WUgj+ zU|{VDGJ)@3o}8^+_;!Ew(!xYeVqoP%k0|gFdnG>^w(1_n?t4Pb%88=Q^Nx50-h`>g3e_2o;f1+=z6(BGGmtXwIbGS~+A!a!0KXGgeuMhV?tZ*_ z{rg_bDzCA7Z_jNh*Hi^D;M!?2X2U%@Y34O@Zr-@9e18he&6*rbk%C8C%Kl9h@K_nX zAh~zwfTrMFMW=;Klv%O;muWmDQ^8;atU*3%pyK`#u&#gdkO;a;$hlp_|7Pt&tTHYR zMl`J0%|@+EBi5#>=Di61X20UY#1nX`>aRi@ijiwgSxc`5LQLeJ^yK71Vyyc{&~GA>~N^KrA%Xv5P4y_xrq!=q;F zB7*unQzR2lG0x93Na|9+Z7p)}&njR`9BZYM;G z`F-Fv#V1GZ?l08dv>-n|K)5?j8 zz*zJvzLL){;$B7ED8q|XLJ_inkADU?va$)lHg5ipQnHah6*M}p3hk$o()@*#*8LhUjm}I9q-n2ilIRb$M`(u*1@H0-K)!ZamlF9y+ zI1a7EDvYnq^fbdpHf0N~is(o?tol+;I*#Jf_J(JZ8_h zqSMk;-?8sYcVq&a%0I-#8>u~%%X~10=(zj`EIXh|J))+6F#+ioRDLIhX&IBA zZ5In?ez5-FiV}HgBr`06G{qg(Q-!_tJ2n@8SZg7S89WURNrTS#3oBQ3#FO_4t~^cP zsPLd4mZs)~k>ssv@BdUU*1X#+nX~DaquWws^Fd`KGP30%0deV5aeqh zFfAwjx%kumY4K{+-q*5pTJo~cj@+N(m_v|v=KqAB@{+eVv9(FJ;q5tCjMk48f9(Bw@_<9J`ppZ`k}>s; zjl&32FtK<2siN`HUVj0-l6tufG3I}FnrlCNk;>za8@8GM735MAStC7-f4fz^_U~&B znhbS4<_{~={&PfjmmQpXy{NA)iq*6L>Wmnz(d?4L+#QPoMtF-4l!OgvW=HfVu@xBS zlYllXeH6T>oZjJ;aSVTaY=_h=C}IjZ`JbK4HH$&ZQZaC}>WV744CAGYpnQ~&ro%7y)~L`u8?>ElM> zbhzXPN9XdA3&KHFyo&o88Y?q3vtRmKu0#w3nY!+T5zT14EnS`|i~x>IOjt5u_;S~F z97^vGc2^!l_IvsU4PmBG5X?S8GlL3NX%K$2+j?b|fSDglM~oRibx&&>Ksz>6F1wFX zj%yxO@256ubpba&NYRABvf zsFxp?BxB6y^9*_UyoXN(F8T7OXNrq$Eo&$WDe=(V zu^l*hO)s!@W3o-j4vUj}4J&Re^?5bsZp^SQ<7?JU0FTd-5`t;i$hSQCRKM5UOQb!w z7B#h^6-14Nccu%SUZIK5V5NuM@3(-=S$1RevFSIWN^yiX7OD$sbBBsuYQF7wzo}gw zwb;Snpg|$f?M(7zfK-~?GZ;^w9|U=sN(eG1NWVF0?u?(!&&yPXcM6H0x?JpZN~@ch zlW35(=b9kQtaIlS^)VWjUhGo=S1=+x+lV&LS>dpAVJg0t>aU7C@81E^aq59M)R|t9 z_QJyy8aX`pO)Ok~um`U#OGUTe%FGtIC&RW^6?0 zxGE^0R}WlpGQV1NPr&Vjh7lN+^&*U!KO5!=&4jXT-do29jYS_V8 zINVi*m|Gw=9B>Pab#s>F2S~wee^Ry!5oKqn`T8&YKDCei9?CP1hNu0a^@L{PPoBtRT^#$tq$jUthr6bV#AF zS^?KdEHOA9EvfeizRKzGKulEVu1uB3Uozw!SI@N(G|W~vqeI=u^zOgdc10I6zwL+# z@4}bql@(1NpTo}1*_K(QYtO}l3ZqU}ZkpA6tZk<_2t?<*vf#rah4+`2fz`5QP}^1+ z-u1L`n_?lN;#aGv;^3$7yjVETxah1HS4?O0(c^yTP=r@lHp+&WxmxF;7jqN>^zlS- z`!^ZA9gr;)pC9DLI~ud?^zBfg6y@vgLcQ0JQ3U0T4QOm;>#3e46c&ty4l7rQ7@w@u^X zupLO$AtwF&9t_Ve@Vhr_W{`S3qokJc*E|T1)Eckv;lp^Zw#<}}NQ*W_CF@8xQXaFqLWx((yz%PB zct*q+T4n3pt`gOrd8jSOu)K{SZ-}u;_gt~23&6!zVH37PxRSHuu@vQqeG9^9%nF%e z(hn7nRbP`geYVhN{`hkEjQGjnm=UOC5r1A#M4SadQjJ34FkX#R|I?^|iJk}F7>j#w z54U`xApjHyq04BK)7scgTO+3XZC-?RJ2VVM&FbR@oXK((wTs^`QX@yh9`rL^QSo#D+wJ$bJ~*QQ#BPXq@+BIhpHKQ~zO zdt5R@tJW_=7~N%Yz_%vjQu^3tE|dr#<0P^@5w-JQdPR;Fx$hiSN#4dC+t%%V+#^X^ zAeC%U0Mf69Vf49yEQNBHh98;cf%VH{Ww=gSvQyyKcv$Y+dY64`?Hd1i7_IHCaytoC z%9KDE$qlkVnwAui3%wjP94lf`Xvm*WT)qmcE2CMWGepqX%B<&syD4g*5;W&6S7JdqWZVhSE$KL=|X*`~SuDJmW|7}u@ z&dU1x<7TAh8z`v1*tPK3RQ~V`VU-_zznxw}sDD3vbL)LzLc|nO(fnoK@hci)2a0QE zsu|T$P#)f`W>UxJ(5aOhXF>H@n|h_tO5PF)GDY%!)n82DHdfR{EORA?*8|67NNq5? zJnbD_4n+t~z~c@KQ*5mM!A$(_I>>Vw@%&Z(?5eA5&}RuxINj1z&W1Z8MK}~#GmU#k zDV+hSS~}`s)hk2k>^4R?_9Cd2bh$2a?q#!|`}<@FfR_@PL@z$^7%dO;J@60A>{D!>-+aWHXCFS$?~!3>{o zNjJ{xKb_No~S%%Xz&Vu3I=$2m@B{c5+OP*Av%)Qb4n>?w+DD{R+VO ztYS}ipMB6wGQ_#@QdBQpl7#5x%WT zI$!I8^J}0icvVXv06s7A zN|nQK=l7HD$wehecSy190`Td@JQ z)XH8c`#V)!cS!W!5kTh!Gw-j^S1Fr8$uN6fVMs-i_eL{&@5Y^<{jWoT)s|{N4%@;7 zXDjD%Px#n#uQ5d;tP9^@S(Z5Qmr^Xeas)f{c$A1p)&(PEN)AeOUb78w&pX}%cEKQo zTs<8tpyKhVk2=RoKV!Jk*Txtm?(Cv~w99*}_j5d7Yt&QiN_WG0v8kBgSdnLsXGhpumPAFReAVpL$M>l!pCTWCcORuxdHU`SC^A*?N^=-u6|{tt zXx~63qJgup>{yj5f6ZIM6I9jnp9+1Du9yewA8UB#dgJHq$2dVlw@r-j(j!G8=%Bf7 z=3keNB8H{(>MmGa>NcG=HhzCR-@Se^lKft5@Ob=2H1dFpvzL0w#X4HRuj**?k;q7< zWf-~ZKpA%c=UVp502~OCAFDw-R572RJ)g==quC&2_MeRHv%%<*GXEB8H>_Gf4f$Sl zo!QrQCvtpcU!?`zQuRngQ=1d1m~@K%sO?CBub)06SSr81(6m;GLu0v`fIaMf@ zH2T9$GL}}fFR89njZ#$|>F?xG%g%+3Z^2L}a@ku?U=?$6nJ+w(Jl1G!XqRQ)`L22w zsyOK0YYxX4?)p!RL-VK&v%#cS>O;=~@ZxtFxTwC6yBBn~a+3!ysP7X&gH$qf-uRF; z!O$ej{7Tlh;341YZusDR zrdK9XQTqpWU^z5;Bw>T0VEp^eE*Xza!){8~jKv44Y}BeBqHad$oF532f-C!C-x77yCN zlav#$W@F*C2{*Q_rErjvQ-n?qMK81jkKv}TpQbC%#gC)tMfh*A3h}OYe4c>Qm0i2j zRs~bjBa&X&uhoMebn(`o!-gN2pDmyg)#JAX@c01MsbOcWE@urC?(DSeCbwFV0|s_& z<1)koGQa5&jugLlFElT-i(XJHHj)-_l($f*%;?P@M6m{`-t|79f3}<2{*DuM>{82u z0WN@(w~c2VfL*xPvajpQJtGyRtQ)OPWe+@C%H@%I);0t9si;5bk5lvzsx|WSy;|M- zeV;QoA(8Rj?+E+BKgmpKRl24lsnFCQ);>3Rxh5b)KN)Fw)^+GrW%G&zgRu*oJ&%6A zU#8C{a0t@UgC^65%zgFX=QJ}+cP!Q8OD5(@7eOv5qPolgfqgE&XIGmQ0SlM8JnZ@YC2~}Zjr8jyJlkHfUp-<7 z1c!pwQqO|*$X{T=HpZ$VtCF_Bv@EAs3uW#$WVs!mgRBj{I9C#Q(}?}_?Lwl8F19|d zBw@5fbC<%(3T4$m`*6#GEQF4nCr=j)MZD2||*GZa>`0byxlxnZD^+T5%N%3g52>0cwC5Q{0M$FR0(dBYzNd zBYIV_REoDuHpLbyQ_rIL;W+?LU+yUGJ-(_>E0hvuYM)KKHMdlH~4lmVHpX% zJm~$hXA3--(Sde`jp@ed0Sj4iLr}Kur)vcKGf+FW`PVzyQdJqY3yAj~v#fAQt0-Fr zr`ahk+Ar`KpXR=BqhnPER_l7bFNe+1W0(4$&!;6yhpT|@go)yNj=K(Q(h_nWxa&JU?n^VA7Qie4QrqXusj~H{Q@gG5f znJdEuY2z>ST5afw52-W%(2HvVuj#vU8gb2gzMS|fKn5jW^HW=dRUKu%-$U4Wk@Y1z z{_O<$0lFJRFNFW@j^ct^w9<>eKQ{50kpNcTqke=5;l@Qh0J(OuP~d=?PYME#`?6kS zDFK{@h0CO8-xAw{d^nGIAoc(~kZOBea40hU?S*pMhg>XTcD%2?&3C^LAvLpnNbT&K zRJCJ%oMaO-^W8FKz4nbJI>iFgGPvG9Dai2*08lUv;XqkgBD!P$wP=W908hZPyGqa} za62|>p76?y&@tKUie9EtH|m>k8@?FuQJ}aZQOAf=WCTGj$|Xpm&-bskP1`;0w+$#N zcdLd+G9TZDdLEMHO{l`FTDU)X;+J4)hhlN3lvG|Fg(s>db{*Nfu6=4pW7PDhr@3Z8pa}Q^)S)RXQvRj0arA?VbHNB$QpKXUy#s7ldL&m4F~to1EkXL&R!WJk92>N``i z7Swb3GI3>=30u>yYf}E^U;kWjUm~(R)wB2)fO&Kc{YmE9gVx0%Xfvw}&{i)0q?XQ} z8d0+w$ci{_(&(XZgW;y#V6j3HOhvJ!Kfw~Pf3 zJ1PX2mu%%pq2$*0P-jnEPz$o_2;HW1YKtTXb9U#6$qd6${E41g8Tg}N00MFJu2 z?t`=d#QUFj2CiKc;|3CVO9QVL#|>Aj-v3I_`*#2IPU#eUXMhuyI15fe#&XO3hmK-T z13^>F9R2z=4YnBe`wuSYMG-sMT~5#xsc^tpB3@h|K%5M%v_+wW?ek;fdM%6ioXB@uW>FHwXxTy zLq{**I9y8ZeK{>S?LCqQu#eryOCxDP0e2;WnN-j`^9UhH_eQRqV>Uv~3us(Z2wdv< z8l(`R+9|Ng^O^%-C!GV|9aQtNM%0|oGDrP$)!C@@;iUEkbbE0DJiLRj-~%2ibAFBX zFHb)>N}e?6h#bau(iwmsOsq5298t+FayBu`a)6J4I@l>1)L~T)Ij3&UfZU*LgsTSN z{X5Z0+H~?}t~{Fk^RcJ#cHI_0PHKPW12&+=JomnjF+I_6vE9fEjZu_fpIM<{@&bHM z%+cL92zX}^6CZlI0ft>8XWC?;h}IunPO}=8ve28ZC}XLZWVi%1NK!eVGLCA<)Q`Hq z#x#S*^ghHwcy3~~>dlTCKWysx8ozz|gNTBP=_-UyGz8!WZMlFFQP1mc4o;0=|BRCY z=QyNqDON=O&{{(tW&lWMQb%lA<}<=7Z?*wcBv%F^=|v5ot#>fsgTD`({%D9icX^Fc z)Tbd%eBpE6_AQC0vJ2pN5GFm)IoltvY@=eM&W<2W@ z|DorXN|9gs*cFglNp83T2oSi2WUh>y5L&<@O2`N1gnCa48piy5;v@tM^>b{J>Wb@# zHm|0gcC{9ULv%;)3f`rGIh(uOfoB(8>rCyGD9ie zcbD|jao3rv=z-VOpi^1+bWy@>4A-grkyyQkd9_psj`egcISz}I#;(aX=5C$5l(}n> z3A`++SocwiL{5WR^~9?(R)}LjgiAeiy#04NSv8#hsA7U^xQida6}(qB`A#M0&|)dI zFCBmISQNNZ(%0*o59YWFQx8a_eVHI~Q*(8Bi=C$OP-%%SgdS=~p;TP>_o=14iVT!o zOV8`XSU43FA4kwjN|^%MruS&UeIG*zZsV3-5xyg# zJl6P`3G*0r_1?0R9!miN0ljdHmGMM4;G~jEF!B%@)N7qql>n-DZmEQXGXyqK>E9BI zdNwP)&|tiWN~g7D0nJ4Ai7pFc$oYwiX}cKPt^z|Ch@is&W`mjsG`3_-__Xq;y7xF| z=cqslIErbbvuzB5!%u}Ps$y}ED6&MKm~ zo6wq+sP{PYw2BCdo*jw0z92Axrv+aGik{>(>5*IKkG9)!x&hRjTJ%T`oPaLqHTupfjx@C_NFeQKETJf0cQtLG!vRPL5*=7e01Y_cwL*? zR0^5)@50^cnx)v&Ux7~M?En4nQ2_iCEoiS0w*U1eSMcheI*ciW|MPL{Son(tp>~AJ zV#^kgDK1wU&9^|coxM18+Q1vNZ-K;5qCbH0g=lDvDhJ<2$BUW|i|Bpq+etTF3x{;z z82?%(TeXhoYmKlI1&o7?99w5eXydtIk<)%_=cv?GOBcM>_E?2NA&S;3rQhF#7Pg&N z2HAG+e_#Gi6o~;=3b&Fbf8wpZU*&eh&jXA-(axw&y^$H>#|YKQ}xcc^Sq# zxIWqcJ1QtsTtoEMCT;=JbOZX|QNKX9p*aidtG3rGQ$O%(;I`Dsf z23{2y+0Z5IPoehWVq6cj?`v*lZ$vkUei#te6)SqWrn=u1=-9L#5EGw$pM(`Y*d_)8 zVA$P^?zOp=NpSx6zO^WI6rL=B(ZC-ek+RWYNsL3sy^y4v?wczZKK6OzJeZ*MZnxr z!E-)cR`>^)-|aB-(WNy@eFEVD+J#c#5O)nID+5Cr595tOYXm}oz=?W{@0OgF#b{wkdLpg&8-f6=nmNVbsuUsg=BumfKDqkzwTGX2LN^_ zyqSI`oUPA%)K+OH09x99x|?8k3N$@fZUx|<)>rgjABAN}VdTF{gq5xxwLhV#xxUfrV4kbc zY5HGV{J?hwu)ada?g6wh*&o0e6OH@-U3NRh<_-u&*^*!`H`|RhFd}3|4&qU4R>l^{ zL!q64jKl%^aT-e_`|K}=nj1D)G7k#ffI)0Bvv0h={7eXz?Fp8`2i9u`r6;s4DJM(7 zJ1nMy_qJW1N`Le*igR6na}kaLWgl2=@)e53nh-PF#r&nK*r=k7By8;T-I^IJuy19$zlFw>H?+m0&P zgc)R|2%TO9Z|!X^#%8pE$Cut4+qP6-8D{=+=oN{C53pl~EOT$bIKa0~`vntIFvS-3 zjC+vyweXhl&G(USQ%vcq<+Z-gyH-QU1qIZ+ zwUJc z({NO0nPJ)kTBSvcRTSjQ(70creM?`LsLR+;m{CcpHwR$D2*W+!|FtB2U)CzO> zQ{Xzcn)k48N58vl)46#Ql#Ke55N>}4=lK?&(k+pns2mii8LT$bZEHIQKrSKvef)6IWA{u)x9-tqpf6BOops;z4N=v8=AMiXrD(vU4aBL{f2)_HO)-1GZ| z)>@@QU}$?pQfn-BVc59!Ha&w#GC=o*M8m2dgH?`uL(l(iGi>LhJE_^C1P0TyCtu(T zjBnMK`u9o&D;@p)I?tikIo}ftzdPQfS3=X7mH}g>(~57_w*!iRfjs$p+_SaU271x^ z!{C6&>?NyBIN73>NowjP3Sh{}U*wtnl57G0M>ZSLlIza$J*-`-Uv%ZH>m?XRiS-ya zsI3fg$)9=>Y#YT5n1C0(U{m{&5J02mCV2+_*6Z-SmkCDF7%?WH>DHR`c{@vg#Z!+)Y+6%`KORgAx&CiLBw%gA zMqbq4#K<&s(9A zr=k;#(gmZ!KzsnB^tN(s%gTk_3{c`+<+X#D+!2?p{-Z6RM)uFgaD~!+Y7s56)kC&W zmTbBVmS{ESm39fdw&LW)b}3uQrQ2LxV47ll7qqaW6~vN#(5l?he9pkbD9T-JSMBBp zmQMh0{=KGaZ-4vfX&1`P`pfVv8+{CV8hBF=*%xxV-I2e&(;s(XFT6{=$_kaFCjlNK z|KInz=CWq1Odi;CBF9%(yf90AW>n`YYLGTQh-YwA*ZHcwi3xtX zKg$(>SjS$$d>n<+T_t}7Mr8@d@Fydkpkm@rI;b4Y7B>620l6M1YP(t4>Z4%;_ZHf@ zL;v&SK_S902i<8rDnn;n&Wb$OyN@gueJkV|bGw9yBwfseoX$T2DxmCXR zML9KW=2PStOKjKA?Sj=^OdLoJ?YA@K_XY$H+kO3z9d^Y0rR}8CStZVqHPL{IAXwO{~7^G#>4V}Bo0Ob zZvXl`=vk$rmi)gV)QM^Dc8hFmyyLfPc>wEbG-2xRxN4B0Hx?$8jrot8orT6Txp4dW90i{DXyp`WzZ-xE(Ed)0In?4aG;JU{#EB&b{^NvK0IE4BJO*?+ z`xBuywLA$@9KWf=#^+#B~|^_d%t~xnXUW`g+RcB`=9P zE|HUOJVdrt?TfA%&x~SxiidEr*MopSe;)?dKQ#b!bGX1ni7;j(cP4^BuAYSy1y!>^ zw;izDTWi3q22cTBo-+E>%3^m^b45X1GH`6#iQCsKgI2b;mMfc=*k0aKHlGZzS;&a%S> z7)Dao1C{+}YdJhS=OAO`%CWXn$AY7N$RKJhhgflj+^eHYc5qafA5v!yO9OKFBYENw z(jE^61o_vg5x9&ZPiscCal`obz2iV+VrhUdv)RMs&`VN!R14!0fsK5R-}bOH0--dF z@0@YVdUfeBRNV!y+LG6|2%l;of{|$L65q9NDxO%RcD4+#2EZnfugy{4S|C2Hb{Zfe z3Q+@)HgJfAh4Xwzmk>)h#e$?E~Z+ z8Tzh8n~@jl-2}8+Z^{A@+*m2h{B_^>2P?_t+FGjHH|Jzw@Oav2E&?Lp3OnT@1|FwB zZ9TQn{5YKHH**{G@1gX1NWW2ARIN5FAR=2Txe02;sVJ`(L0@cFIF&pg9dkcGnHj7x z?f*ymnH_=!A(Yy?Yi!*fTz_$#36f~3?lSjn!QQxN^Ma5u1A-a|qZ&V0DgUm)&(xr7 z@awSp$M>9S>z-ax_;mk??=vq#T6b5i0!e>=^(+8lRS#6p>H~{r_ix`h?+SEh-v9dMqwgU+oT*=L1Ee3=%MbfW zjpLRmvCrKZ&_>W!TGWoN_16;YN~KE+4s|71v;w{718M&>Z3wV2kHcDe=CN57b|0Kh z&}M-jsy@u3JLUbBoYYG7Mpkw2-L&_ z`eADKYSxXBdm{i%qHvZWD#=GCvB*zv4*P!qVcI+h8%^RMFke3~A+u|JGxPr4O!`p4 zErLVIPZnVM6D#xp0bn|V0peQlH_$%e_^V%)vUWluIvg4e7)+D?FJX(c>Mh)N0Cp^Y z{~suLbomtouMNn;Vs1LiUcT`Jlh&4GO15bQ zV#CMbc7QE!;sJAXH1SfLgD)&29wcw=$hRDffRthtJRny#Nv;Ha{tQIIB3l73qNXhX zbGrbzKi422``!hj7ptkvPWG65c<TI`T$pJB#6Fv^`@X_@8g;u?i7cWPk0P9fl*8aK~TtQ$ceBU7mH;)IO!T9S`jp+8! z&$Vm&gG%P=+gW%`Q~U2A5{ayUlRr@2q`2z7<3d554PuaKe=W1y$pIxe_~rPz~0Il&9L4Cv3<>?aTS}* zoIBtKALN7n|2liPN$2sbfDIUlVroJP2rU(&M0d_h!`0rH zWi!}wB%QB3fi;9jm+L}zIeb!Ibxr`NQ8mxhcXinFU-5>&!u~wbG4S;uU!Rp@=Jf9 zUDEY#>H8OQmR|{@K0#p79S$ECFIvPTmh_i}mc4_im=5F1tGDp?&3#jv?4&*S%KQoh zlE=-e0{#hjmbJ2#ps{}`u$K8c%x z@OCO{IUbG-bw$^wHtb7?r|)}##ozO2Q$(6PNVRkyG~2={@MCHI_TyXs`f-oCxzZp> z7z3zgqJ5*OwJ@qf;N9R`JRDq&^hiX3aF3fwoP5UMnOp6K67l{33q#%_AT3e8c^szT z5s>DmdqcErLchO=nyK1P-wGo#fbf9wP&Oh1Ttun5aQIUE^OCBFpSPs~2kl%$IN;h0 zy*r@m&_{3w;AQPBjvOfCum(oM2YQ2MK}OdM#=Jq-?tW(U;Za^(TThMryWEh3LuV*! zK#>s&KJag3LHp`%hL4S|fUv0w5ljrH4$bLyK*R(mow;Z6{D#~meWvwtn!7MO`jein zyL&-is)f%)iNv8TmH)uN5xtQfStd}7C%PnKu;X@EhL0Yvd zH-NSsu)(YK_3z7w>It#wKTLO-GR5_yx@(FWC?a$MCEZ86M|0bGnnD zOvflQ`CW4Kz|A|OZIwnrUbbQYf+aFM=|`SlqGd?f{F@?9Fr=X#0Xm$1UBi2R0^JIB z1oR@rQN1g?EY97h@!~*kN{Jx?5Kld$SiDcc{=`%7UdR)C{&CCN#L-%N6m4Zp?Px`- zprPKb7`_CXNqIfoHV$0J;x2u`+F!|MTu85U%!AsbBX!Ir%#2+p6gysbkjG zED(ZComj@k6RCjtzR)wawOkmz_xh8QfD|+B*RuI15fTrf*$LooW*HxZzfYGbrl9w; zzfVM*OuI>7_l*m~h{|$cn*EKhA%Y?B-5Z0C>a48|ck4MQ%@f|vpLF=EWC|ZADuM+s z9}TMa-tIPVc7~eXodr0-!Qvy(U8Y3y-DyWmHY~+vC;mC-F<~~_miu-VYFbr{hqX_2 zc_oW)igtx9W+ceii-YQUsj1A{xwH6dc+cEcO&6~)%!4Obbg@bEG-wE@ZJJ>aAz0J3 z1Pc9&7ir-B>70K4uSHd*XS z)Zae=SU$W-e>4yYH0+I&J^FnH@c-c0CxE+OMJtKAw6{g87(jATd606)kuQ7oD#`)s zryRf2zy++QIhI&4t}x1MEua>&ey(-kqr^moO?=SjzKOgn1sJI)Neq7>D_(o(M$Qe; z7?CDb=`2&}?wy4|rS7voV1$zTr961;vZ9@hnN(WkZZ<@8Hb9bzQ%k)b4M2(Q3UNmb zDR8tyGa5L0UOZE{kO`yL4mCK?gef$Cv^>` ztscsQfCtcSSO`rLb^rjZz0wI$7v?|eVg+3^L&!dsa^L9^hyk@(;GjazBm;`_p#hr> zy^qXAfjfwenISdRKu2zp+@W|zAszt4qDDO{;b5s7!ToOhg$yABCqUe9x4Q9VG1L45 zT=;L09pUJvyR_)nu29v|&7*+R*~|TCxLhi-*2{OgESNxA5$BwGr}|@%O;t} zyDlhYSl536kpq2gcR*^W3dPv#Pl&$J5OtaT1)(wLhVi@8Oja5K3_QRiOQ96yXyhOiY#)Gz|+;K4n^SVpgoD+SQF&e7n|?l4tVyV!0j1D(lsX1yz5oz4iO z(>=Z)&w_B9UZnXMxGXlJW4Vz-%JHI)b7707D5t>&1He;hq{KS^2oQ{=j6oRUX~T1k zu2$`KgJSV(1>Ddo9@Ncivt5M1Lp`H*(;nzCj}nFYL18ETqQP|c7OpqV`z>0D3lz|& zql8g~_t&D{{OPr*_xkW$dCQQQxtzF*oIhyG6rb-}Tz(?wvSx1sHE(bzplbYW`tcSo zI}vcvskAkB1FHStn#-V~0gex+PTa9xgf$*dx@p+M z5`x79neT<$$=%QZWJ|U{`B7hW>sCAW-0P5@#YkS`47`6M4mn zz-*;jxYdmUo4BcsuMz>XgF(F- zNSO@G9f!4}seRMn4xn*>XDGl!_pqN2ZOz6M1T4PJx+XCqhKv}cO zhnb7VRDAo_9fb3$E?b; z!Qk--XTF)cD?Q;f0GJS6T9Mz|+LKR;ZRegTXY)#QrE3bJgLerfTo#-+_(6Al`*-<}pAr$8Wk&h7z4x}9UbQAqTre~ur|H_$lwKuB*=y@G zW6#ENS4xtxvej>yh1@EHV;5y>?4QjglP4?UTTk@*2om^C{@&Y41FH=beSr9}q;v;_ zg{+yQ_;}d+P~;;a>=p4P#%#EZ&FmDSK=zTp9dbF{aT(>4!|=*Mzva5NI4+0Kov6%* zX^Z^}9w|k%suvNT-m}R~m}5aQg-6!6${%pTy&CK9`o^a-Iy|gYC;%HVGEVvV7OBe$ zIoY1qq1RR2Y^5{NTO54(=p`!aO8#4J)RQBtVp=x*x&&V2F}Mv zpDEUS@?EmqU<1x@b_am=IAzgNjfWtQUEcug_Qp*~x+*og6S1DwXHN579u}PaXIgif zepN_MT|_s)S}fs*_%jOD!LQT0B&vVub-n8I?&3(w)g7N_qdF-t|NFf|UQWfcpu+-Y(fvR!;i$Snv*6_AW!v`(Vz6{-MlP(BCAk0*X>zBE0bGeANHrkmgNGn zK=tuS(oyrD@OldWX_%&up=i2t)+OM493Zhcja_$Xr4wO8KQ1}SIkmsZ%`TB2p{_7^ zFs$u{sLqddy(T9H#f^?lZ`CfHgdz?^=-I4WU!=<8XjZN67jPe4sB8$CIvY@XYmfB4o=+agQ|9j^ju%(OGI$vHMI-_6>tsBwy}6QoZvycd}7)N8>1c} zM(*yAx@nLKAIb&k=zm_W&rM&Us`rPFgL=m4X602i8-iZdEzN#*onZHwp&4ob991)Z zDl_8=>r>ZkK1$Oc(1+_ZzRlXvL#6253}(KwdOLoVruda$Xf8KY$I}oVZ2(zYD#3D7f*m!G|!}v$m@l`4Rgps^#2Vs0lxF)eU>)zgM#5{PrNL85DhZ zv-`Hu>1q%pvw&$U3i?ehadzK1ka)i7AUo&EtZ=^W9}BaI6iK&Evpv&xgl+xZi*JhL zHgnt_u7@0hO}|6VOWnhNA0@U^hZR$X5#=XtqnNEGB!fkZu)hq4e(%X`M zbJVb+0$j(L;l}E(8Oc?`m~^k2(l+m#VeS@M_9jDG-K_isNrx}5v&Fp=p#<`KWg@W( z^n!ek!&xvri$2k+a@`1Tp}AYRk5NdyE#1MF*H=M#>$GR-Hm8NpgorioB`<`dFg*m;nfOe4iD_4zi3^I=d zyKEBtnva6VqM~+TFqZ%_?WY24A%FH5eKjs)GbcvzKduS5VD7D9gnpNv9xbbET9!CM zliN{$E*8Y(wHg89Y7frcvNX@IMIOK9k@oX##JLF6pW8|=q%EbK&1@NofI)OINEs|E z2!REJcG`(BcWTo0MlGH#>Q0vzHFYN-f%pFk@aTbeYCZuI|0@~+6Mr2+?2EXr#ha4O z%c7C-ob!f|5J5>d!5MMWKsrH|z3jAMLMaxA8vbB^SPGt#T5bD~l{A6QN3_wvwQ%pA zZ${br%Nwhc4S%t#I@_e}A%Jad`#>TqCw+ih={%o_$@h5)*uWBbX%kJ^Ani&3G-nFYS@Ust+Sp@?>UWUNV#*W6|O}spEPY3Spx{xG$&vw zBf)X@nY8l6500pe9-EoaaM>;G`Wd88DT#iiRo^l{sm5=^%$IQZbK!gOScL0EVJqgq!qpg*> z!w4n*7>!<@MDNH2A0lmq>Fu9g>D9Su&}+8*zL%nZ+7N^S?`K4D+x-!^>Cid5Sz-H> zc6CBlg1$g_!t{LWAB!KZ0|)|ua#4c~n&n`NfWpHqY-Cm??#eu?JCv+Enn1KM#E=;) z?>ixw9=cq8{a( zepti~cSQ^#y@EQ7r6j?xitsN31;1pRe5Ch0 zVs!~Yt*p-kqH%Zd+aZ>(76HUM0#_`xOVaSt4#Ex_^80S-!KRD|o#=R)G8?OKt^3oL zmu8=mKXn*@bd+u}+*2RzJY2Uyu`B~NVYq&{TE+l&s6co2DF9l)y!W7mW_-d&gI1*h z!)?So&@ay4XBG{>mxX2?e$YPd6Qi*bdjTA)*t;)wF1Y<65wZsgZls$Fr8%E-l z(cYanV8)k+EpDXS;4bIWZ`6X4g7AW}F3E&8Ku0WnHPA3cz8PoHp0AD5@Sq%P+FaPJ z&vR(djrV6MywN;4gG?U4bc<>7j6_yv4i&_&dzd{xPm+7tpIMb}0r$3^5E15}U~7R$ z&o3#jfkr5}2RrE7WWV~V1Lawn!~odcO_ZTluY(pl!%eb6@v~>bvX2CDs)#|mN+z7j zT=Yi>T@vM9B+^6mzA3$0GBk9r_5ilqYDDfgkY{4ZIGMs*oBeiDY8=KChx%8~N7jf- zJFdN?Zdcp*Cl(jv#Z zyBKZx@Ynjww#IGDc3g(38jqv1j3RE;ZEJj0^r3=qtpiy57u-@mk@*Hn5_7XRa=KqJ z7lu1Y$bIF%|JQ>oQhh6m6n~zis+(|VV&+0Jj0Cd+MMh|;UiNQAOex3Tr60!#w-&s( zE$^Ijy~_4WVcvr%3w(kXc+-v+5aH+5G%X7;x}`sl)xlAPnR zP_!nm3;PBQW(DK}%dQzkMq!=d3(KxtOrkwmSqFNG6T|{b*!vuLxnxF^8a&LZJ zLnieHghkt^JX3!;c&YOZF3(jb`-$Fh!{@Cv^0zUAvbM;e>HQ9p%n2Wo^wuzGA#*Qu z_X3203t4QohWkHWrk@nvZ@-+aC)eV%b1pIcxKYawO4Y9cP%fJIC{gxfIq}w zfgFNp07Y*m{bM56Jd?{e%0bjhcAtqP*-iQhlI%JzREZt_P${uF*UD*wi>WykF-1oQ z*mxQ(oudQ~BK%VO?U(VK@715h!FU7*QZ9r<7{yq?*}1;4vGIGge6d~J_2c2;kO!Zi z?U~)aJ$ldi(|aCoInATq@afLM2OI*Qg~TpC(~1Z>xW(Yfk!^yR4Lgq(f1mq(`$`Iq zWSaPX{k^ZLvG>A2rkLeU108%sLG$4Y$PMrvY|jN8vypNCtxym z2e(9z75=h$wVl%b)qRZK>joJ+`M2WyikrLXQy~V;i+3}fi8gkYj?@3v@T^@eeHKyY}*_B7TCsXog zkxHpG@D(@B-#GwUQ^RU%YBG6o4n&uW6OJmU^UN|AR`Ff0GhIr^?m5R;apvgnU1Y!P zwqSE<-TItpjrBz!Et{q@N6h&du~PGMlmvCb@L0Q{EUYBe?)!m&FLq7wTGr3gsN%<1*QCD2o%PV;I&NGRGsEnde zjb9UU{mA;{OFArQl-lwhm~A&df3b=r!~DLK^V;&Nd5L3e-qpt+StGN0)&y{VZy2EBEQ0{>hUy%WHmhug*zSqEq z$LzKXg>dSPiA0|Le7HU5Yf=GF)t{!a5BhAy$pxLgGZd5;!^_(M^mQmf+nHKb?lIaY zCYz=a5!Rv04(%yfD-Mx@Xo23i%u6R@s5ifh(~Fl(MZ*G5-ukr_7ts~JI&`1o3@M4H za|QYbLWP{DGf9~FSL~?)UMec4Y&#F`sd^dT+`}z4f+j!%;A|^6ie^`N{&Xn(wcr@0U1rKN_6# zPxcb<+s%x6VJJ@d3URFU);7jZJT7))P1d3Pm_>%o=sb|K0$s(E*F{k$@5B2IY`S1N z@6(P?V&Cwkd`katKJ7Q2ga22CPFxM8Lu*(-*kR)P$hSDn$PwCbEkU~prehXdvf`zy z+@l>XS_AMC=Dd`h_PHQ;_lq+hm=bY=&o!9j=7?@f*~#HUk!kPh3p7V}FRh5sa_TWc zMX#~rAXgn=Yg+j(91%mtS5%1_W?m#nT7Nvtr(i$+a|eG<*x!7UuUaY;dD6wS=NaeG6I^-Y zx3X*N3!cj)W~D`6#lf?2XgU{2tkEE5zQQmn*rgh4*!;yRng#|g)9jW^FKV8D4cqEO zcfy3pkyp9h_A=L1khzb)rKmDBIGWsz&yO4AlKEf5e)zkT@vLZIhJfBDB}zk@mV}~8 zJ;$$Fu&ULS&tdlta^>A_d9AM8qTym_vA#AF*sbDb8eI7yzqi}c5VN|JEM@yBuieX0 zyeIp2@r(4R3Q-AKn>tnr$H@ZJ~1SencJs1Utm!xQ6#BSn!aQ`IKvZLkZmn1`))%%Dr`D!@BG-#bw7)a^6jYBS4yUK zXu$oU|`Ro=nk76j!Dz^_QNqIi}xOVv?r0!3j?r*I%$YQU-vt{JjqVK0xyYv>_ zvKh_Hq;*trJ)11f+YrCgZ651|Sq$44t_{^BI5mC<nyad^GtjUT23 z)-Lj)+`@eU<3weLMAf{#@2HNpxe+1F!=w%Mb zJ(_sY?isJe=#~+sdGK@Rk1ZpQRt3j6TeJoif`~k!mnN=*Rs6lChk6&|chH^fZl?{k z6ckiYe+m>26mn^q{#q@tO^ccLIiOp4ds0q}y>VfA;rK&GF}dI5Z9(|ffth>X&*XF; zpzNjEle7}s7PPO{9}jY$cu?JflYcqB+_8hfXZ7qaVuy*ujQ0CVA2|yiwC}G!xGavf z2@%U39EB#B4^UgIMA}d0Elr@~TF@ImOtNz?2Pb#+6{k&hzc;hZRkx3rNS9+Q&y5PL z8nihXM`?^Zi86a0*pR;R(t`_iI6rpO5z2f1r+S}`ZNYt=+IBY9chaoqLn8-6CL@WY zE7axd>-!N_qQ(HdUdFDO&mu#E=@rHs8rcZiCrtA#pG;|*?p^I@8*GR9CXLow|NNX^BMZ$qo+l(jT&&)5VYXf5Fs)VxY?Nx0`oj{_m143!2jQHXHREfsWA-dXlXzNRf)so+F<7cqIU{ z8D{B4bhN$8RL*ym6jD;j;(4Pee5^kyJ@IYwVAsi2ADtt36^^ph)0dMceT7ask6M|x z*#&%!IsOS!^^}C8OwNtXRFpIJaY*s9@a0!~DET+C4v=RE%vzMYIinfBx-OY+cu`BE z`IWpLBr6d0Ey7fzm>crLsNco51n6~D>rbhhn3J2@>vX+zf2XI0UuwU7^#iwqLt_(u z=DcbAYpwG_Th>-_FgAyveX*T2po!D!MZ1_`=H(~KCRhDr#3^6&D^T0|KW*^6Sopz; z0^I@i`*F2o;;slwA1IV-vC@{I75UCx6(Tr(G;Ken@Mj}9(74yn6&ReEm@=&|SJai6 zxNM5fdT8zQ!O8EPhjo26?J7TyZ=~E5xkbxx%)v#zae5nwnzKaSt{ zW`QMPGT4DQ7@Yp>ywlI#?klUEb|&>y%q`b$F+b4ZYivF03pOUh?1-fF-3L@Sc$MEt zs~>5~Hq5HoeTr(jk)#@+_~whzYC%qVkbY@KziWv&VB~n?w|l)H9`EdK>QKmh-Bz{Y zKRK7NTSvt^(OZV+Joiz{3eW89fG6i^P;NXR`H8LY&tA~XlYX~1bj6eusEF>|aa?@? zJKc&~qcB>YHv2V|d5r4a8LAGx-kon{)Ao3G#FUOAHWiw&x^2|z5W{0J>qGP_n-2f$;dzGLRE&#}PI2o)tOXG_;Tx)!0`-X}02Q?yXT z$$MKBpx57f9Y<~z80qo)q@V6;>qztRdl|z?e{x>OqSV^p;5Dq=5P1W%VsByr|62?f z3&|C4-m9{mnu;IC<>6h$+V96sBF>jfWL(xtYfNG=0HA z_F?5M7PKkiQ2mgY8GfxR&w|@&X-W}SWpNv%;izjZJF?B}KVIG<~VO5>G4nKQ- zKRT#{yH2+DQA)903*n!;G;Y3yYDEMUuA3>{>`q$cfb z`tS~m)3LD!Xc_&}c*Xg-7K}(%nr76OW~s}y+dZ?+luGCF!K-4!A*PYv%Z{9-(zn0A zYLH{~l$$ClHXXApFqo=Juhw^w){$1HV_}fDi^cJ1jiAZ$ilV>`oJB^yMX9U0fH$OZ zg0_YIgQ`G2v&!j1^ zaG}&hM>(id4GW!aO#W2$l-wx3(&@pA@??P|r3N~cujZtt1J7Yy&GgfknUX7K6~wV} z_89YUo#EGt#yok?JH@7bvh9CcS6**!uLuCJvb+0)VMAui%Pv;KtuaZq#VuL|*&16N z0?pIDa~PB?_JBcjuh$+?HRI5BOyHXFlFF5>&o$U4UJ0o98WF9?nJd)T+g<0#ckSba zsfLp;$1wo{F^a{CPpF5nOqh1+db#@X7Pj|(%FLvnBJ^g(31fAe!$DzM8;&m8ubI)S z0kKO9~p-%rPt=_?v1#LtM^Am% znYgr|W6hN4_r^pfEINXpHO54S{UY~1)R;BYYB5#GiX%$tz11^NV@7@4J$>Ui5r?T9 zmj(Waa>!UmL8hPjrl`b2LfE^N4-a^+6lbWp28Jdpc z2b7w_Z_g2TuD$fP77iCvtVn+V5S4VY+exOllL{nIC*vcJh|+Z``c*@#j?%=Fx(=1h z zPusVqTnc@xowl$V_7mVgt9?cPLud8E`cY;rKcdQX6`yo4<}bc^EXO!E1jaKd@{JeX z`u6fp;t|~u%9KnMO3{J{!EO7>o7>E2*1PN5Tu3Aha`tLLcSp8irJsh&k20yN-T;=P zsatTp5qt_~+)r{#S_6dmH;C7Dn;Fcf(Y`(x{xdLk050~*F8B!gv4{TF(4lD`*8OIp z`<<2faWC$SVZ~Ec!r438CRiQRS%c(;z%;V3c-Ep}psnf)a9TA6m7Eapi>rIa57S9o_x>0R3xqFpChy!PrbK1&F zE3em|cwjuO_WlAm5i~JIEw74p@k8I&^oUnlVts8Ai2AwbtJ9l%(tn10JNd)otGOWR3ZHjU%jBEH zMU|eg$QWpYMC&@_%Nmz_8Gt8On=MAQS2pG3Guz4`@U)ZMG0L9o`PQiYBzyb-Ip_S) zD9KffXIJU%rg)mq04WfS0EV7S2=;ch*o75s7o*jRoR5&@KEYU)eU?P8Q}456mkDlz z0@=VR-RL&;909^>2O?Gt0rVd>C$c-ho8kq|ocq(`y+SoDyA;6|fHFePhB<7y$Z-zU z8G|)Sc6u(G^V|p>wWpQew%ztvf7jSwgb7ppv0Pa&I)&eH$-M2{)#Gwyjz%&^^@Y~k z?SCg%>YE!}x~;jS#l=j*KRcCu>|wl*&Z@t>m>iAlnGyfBrpw8QvA|~#@SiPU*^8b> z871!+D|$NRMCjS`!JtiwUN>D}o!vbI_JW{^JEIE&NyX$U^hAKZ=kwc}EFkM9&VO7M zu4Nvv$R`Dcyp1Lc?1-XI)_v_w`+Ka zP90M8w5Ne@pEVh`;_$(5$(+&Tc7J&2ge5+vZ(dW>%K4dot|4UNPBq z+ntBbe0FtJ(Dlgf{;H}^dU{Cu%Rt^OXfxu@Pkd*a!`-t>K>6$|C2!X|OVd`waGr;y z(ss=|DY_1;?bQ7zE^q6u))+ye%{FDj=muC7LG)Oy8hR5qqOZt zHO*eA(KwPK$S7a!Q51{dA?90mHQS=pq##1YRPEokf=coE@4H^+7kg8{^gHAAo>s|x zT$-MZDak+urB+zPhLf8T8e<6>0A2sz_c?QI*xxE(>u$bn$b>lawig%G%x-RHDwcD% zTJue;S4$me3Smo$<6*^Z2|ztVBO!#X+r(8p+4&nYy6PG#(VY?;1^Iqv+ua+%Puc(lfa8Pj;w8-P5d~kWN!X$l_&?u9;!7tIX{ef{lmFg>TX2cTPtp9=89sNYeI-K;(L$fb$yxWa z^poTLZhMb5Ck_D%_9<4}v}SFwt~Qk8KCGArt7Kg8$!(0*uPa_Atc}Qv>Wjje!BauN zQvNnZ*aFP1W0m|!JAVx#m?_cf+$*BhEl67>E}#h7-lPC&>PP|Rs2}0x8mM9r6n9Ek zRTvT7RI>CE*%68fY2t|v82cN#i}%3PAZc*mI53HOOMWFv+v&BE$@`H;okH98bzmFF zqlfn>ZbqvyUR2QH=CY!#%FiOG$?B5nGg_$HT{)LN&g~WX)|EU1RY>Zj z!ht`1@Gg^nO{Q7wfkq8eDCAA$2I6>pvEt#0XD zhQW{_aK_TZ;URb-wpctNIin4>FlpeOL0Slad$u@9%v!?xh^ z$BMIlb;gHKO5HfvcJXlbs`}2`6L}AJG_pyd4r6c@&!Ml{9;V(vQZ-q0L!cTr0I!!_ zt#cP7STVEEXeZ=OY=qobVJ#z)_#Xl#e=n@rHYB(%cFzQ8SEX`lOcCD|_~k zSXe-Nn&0)JyDpsjK45q$5TrRmKrdotVcWS)@O`?5`M%yFF>icEzry1=@!f}m@YL{AihbFZG1X5Aag+WqF3*UjNK z3Leg}mqMG{k5O?5ADseM|w8~#mbqsAvMx)#R zXp3J6-JNIUd4iy8r<28sV^_mKhs}qc*RnxpkTnX~Zt^4YE#!R-JUep1apn{7=|XAi zaPeF_`OcnZY|M^)yPuSlbSbM5sMVvZMZwAW&3f)5jj@+1p}^$lbtRtHdg$v=SCAWd z_<{p!T`XDbUIe)6pj2& zbLq!?V2T)23Kum`vZ$Gr&0zMT|m~FrzS|()Lard(afbuPlRrX_bRgH!jkEpzFZl z7N^XpQ6&ax8mu4`?iQ|VeDf~UFu*p{I&0B-qonXa60zs+yz|FcL(Q!$Q>|KFfoewlC zb+w`whZF(f(mioPH{vx&rP&H=_3g3!W{t4&s1RhIi6h%?cVGO-9U$H=@#@@~8K@+f ze}>p`AKra$f^8!oUG)1$DEeujylp{h(&VVy-^&0@(B{VtEmSg%g9j6pylV~{yUeCn zmz2(1%2IQ>tS(zf^Y$ZvC8svAV6N&ccqvg8drYmk^(SfNOKP9`-kTNIY&hlUFGI+2 zqQspvyShpmP!eycZh7Q3acuk)Gx|3u_we-%>nw8l*?75uKuH;_o%PB-dNwt8HTNC= zD-H6~3g7&QH$W>(e?ms&^(po&G$Muj(n6H517SyC!YS|_7~aHm0ZSGlW&7npl+BWY zbI*tCu!k2VWRXevQ-6(aH@`XLYFeEY(DRF5-qrG;MCvLMgs{juS}OuP(E1R0ow1sW#l&!O z0fyAzcXwgJ*dn8was55SQ}l^Ei^LO?wq>u+6dmYX>ZLZlzL7I7IFgFtdF#bGn6Oy=FfOnH4`x}H(xjus-AUuYiX8s94%}d0(_LD`A|Q&tT!rta*JgP zjc_H9qyAa@u!A-#^|CyqWa=_DRKF*wP)x?3pR}>$*(d`FVtjplT_(qXJUjy~gEzBR zsTeE!tcA=dex(CbKgy-cyl1R$3if3#7KpDmTv{6(yd5qPQp`!{Ym1Fi?hsUPzez91T)UARn7{f~TnlvPF)`*I6zg&TFn8dvW#fH~RF z%wcUjzqP`xEmge`JvB2(63iANT(ASmkf1#V3nbciZnUKo)B^Uq5QBH!NBjL~Mgljs z{rtH?)3ZzS^F3lH@9dpw z69;n)3p(Px$CByc*IrTy8uQD+Bd`NqVtIfYK^XHvf_eH{UigkStFYa`cJ@NLK)GKS z3cU^IG@g93PfKV6@0y&c)sDa9W2wID=BLa1fNj8qN+&kgwaL)dS5r`@_5br%$s%%r zfntu*_U8Hz1GU~>6AIYHV3!dkUYZF(<&Ebi&#%tZ zf_K3sR`u(De%RiK^1-I|=&G(5`wVzTh5eRZRc*m>2&z6+aqUVSKTGbZcB2qn{`K3N z)G1JAK{;;|w24_AU^SVyP=T5um>2xBKVc8{{%V;$xVkjM0YQoT^;PL?d!y?r z0oxg$^Tl74bofQe(Ukn@AM!#>?zy^&$Zu{^_)v3YAQ3jm>jVPiF+NDbp0$2|t+2*q zyyU&1!HK_7qNiv?C|lF5D^H(%()D_v0_$|z_RG@-oRJLA2Z0T&;g!CVfmY{q$9;Z& zesXyP;*OW8tQ>6>-n$Fe;oqu4Z~T~2er%R0(ChTy=VQA(I}*Kge%KHgmAo!-;Ajh| zrM*|aqciceCR}9vE{6Z6Jf~xGO9c^`JKVf({zfJvlm`l=L0$hWcJ=9&)htO+Hbd2GhN5D(nW zX03=*dcGd~vzPWY7W{^ibU=T#hbN%^u@T8^MNWv>rt$RPUgzGTx@obR$Qy>w-igXc zT9)mxB;izg2rd>hfYodeCQ7|`LDuCa&J^AHR#T7m9J}I73_D)~xcbrR;y7-yyMO}> zRNSg@P!>N*J1Ben-D0Ut?W60hDd(aCkea-R!>KdJxUjx^G9zUksJu_`)tb@ldS&Fu>&>or|-K@a)HM#2K_42X3_Ys``>~aNj+>2?>~C!n2ry)MyK+Ra$f0O zJ;wFW@+Gr`MazMJLGf+)(p>xBsUq+2l%f|JHkmd0x`vK3aYjI@?RywOaIH+;8&L&? z(3go0ak^WZuJfyHSlC<3?N zZb{;&gpwrlLgOx`%^{BJ&#M4$PP~`)n(FEC;sW9~tO-AA^X>Q7=e6VN39naX=f}yz zQZl|zedm=+*sg>0o-h8co`9W*W!bv>;&jyXi0b~$onx7xFr&H~_9{}Ip>lvKM(Xhb zMf_rd#v=z8<%f1aitJ#?xjn8LU*irmnN8rcu56OG}-7ey%FYx>@5t%I*r4 z-TQlkJ_G*CS{JSQEbJ;$sHs+E?&y@V4`gqe=X*X)-r0{4n)aF*;LlIYS`)ucE|e{H zdl=zsH6K5D7W>h+f8j^aN8~B}L+!xDsC6Q7RTlZUdv=LgO?F;|rjr!63HF{flaWh) z@XsZ4pu%d)xlv#&1Rvq%{YcQht?Fc~#1up_`GZ(vH<7`-`D64^C&fgjl*-ND!{@kd z0*NcRRYrTZKpJI7s^^X~Hyif&aT_&&&D+9h2FC94ewrJ7@R_=aj*!4yhpgDn)|@IN zKcWC8cgATG9okkEJpQD=M7HU*Dt{ju_};fdO z@(JGPBam1<-@5K%SoRj$hV~n~N}Ryd4>waH$`Xe5;AeAt*3r#y+Ap-*V7T@Gn&6)J5u_}^}Tln0dk>8-BK>0FzIK?vYi zHi+fhFX&?Cv)(}|c*jvY;!elL0%JDySK0p-7Q6WsIo~LGOZb1hEvQ+r04xMT6v+e( ziZ#rYOdRmEM*VB4RZRY{n32SwL`cf3+o2$W-O+!L{sfR2R(8#fhgAZpmk=4HVcpmo zngp%`N%HAeeH69->IfG-Q4uS4Q2O>|8gx2nEM~QZ17ETuE5Z3D)QN?o>8YzN3GxNQ zPWGbDR+mT{iHZR^m;+G8&j`Hz-~?>Xu%GQr?$Qk)x)vo)WptYrxKy@Z-u7nHsWYM? zca9mAgHUe&EcV(3rV&v<&jH!U$}Yz?3Nisf#9m@)^-xv|p{o1>CSsXb*tUR@l~C!I z3doRW7r}R7qDSf&S7jD#=VIc!L#qDwrc?=+f$S*rnaiwny4+>!uD(E?>L<$YYslnc zO=4&BXd4Q-vf86H0u~m$x6TW=n7kiOh6{5CP@am&0@lm2gbmSOz2NaX8=9*zVh~yr z-GeoXgOkzjCmkLnYb+j*kkAolUn{yy>gld_LpY@Rd{a5sANJk`&li?O55DK-bF{kX zm#i@Y^IizV?GEOMuHGh6?e!rl!3fGEpDL67@0D^01VS=?%2{N|@#iNC>BIkNeOMty zE5>R*J!q4=1vxV{JyL_oF+H}6rWCmDPlI?~ukkhjD1I+_DF7}>%0B!2zC*42Q0S)w zriw3r1L!Y&gIA}1g1gb=Pb#HUvIiJ|gJPnW8E~F?O?T~JXd@6IQ~gd;9__X{>p%|H zbn7_num-*WiF{@2Zv~*V_4AT{`((c`sA^YcVcHk_eKlR%3dqepg^9{O?b9c`eFdPs z!Y|$a!CR2DnMul+T-QI==)TvRsi>hgm}P4S%sVJI=}={EJ-AsROpZ1b2mTYJN?CCL z-@+f>W?%AW@0#kn$NuJ|uJCxb4v(mPZ*|rogs1x94Z;~<)4xCKqJ0-MmNNYO7`Wk*dvX3ajqK|?jbo3Tx~s&~Ho8>@ zJR*4GGj{_I%lW!4!Z}Ahl{Vc3rF*oLysJpAGgry0zxH4NmO`aTe{&^nb15+9WJg`* z!7|vYw0TKl`|0Btlp2@~<$t&Q`?7}OGVCuVWg6g}vub*a?ObBx0ri0`yrRVy3Vu<% z=Td@7&nnRs3U$+m0+LK2~yD40hRP$_=Vz^ z=_TvtdGf)@zyBgjiKoqn2~b{gfr49F={82tz-A6bxc)I|@BHZpZ9O21wW#XG_Q3PL zlnAPe`ovjC$zdH%nLYI-Z~!(Ykgb|E&)+OrS;G#F!1PC z@^02QSK88JWcIaJ$ssOq%IS@~HcEBN__xiMa^ZhoiuMjh$2yF+H}BEt?3fF9%|8sV zc6g;No++(>s%`bo8=lFXz&^<ZxuKL0kpovi9*UJfDRCfc0bf_?Bud z@*(;m^ErmWG+8m!Y_R8#tEm~m+02Ckr?VaGB>?c~BLD?j+ABI>tP#m~2ytS04f=Zi z9egEaTjNzi;!vsT!&IEjP1-A@(Gh7X9X3BdzXeV-Hko>b-;j0cnpe2ACB9ROo6fA3 zVba?Am%VR1o*xZ?%Am{7qg*y?j6XTR9y~>0Z(K^*W9E-9$F_6 zwHP*xbSXGiriv%6t>K_ck)WLey%!qOxwKgjj0xr!aAVmH%FlmPV8!L~>|m1;*=(*p z#tzp!yu{BH;VTX^25@H9xvrzuyhv`8_pUlYo0Le9a|y%W+SFI_y%Gag;o&$f8CXyT zGZ&wM@6nG5b2VH3LJgwWFHCZke0oj~9t4+y?UIfda5)4blldbLNtDrjw8ibD0DSpY zoa^t$?5Gq=hU9a-XRRU1&GWINbzXMGk&ib6m_qhonTWf zDggATxj1~%vh4I?8T&2SrX0m^Pk%U}$drE2*EN1UyAu(ARqZUMjDPq}uY0Kkinny< zB$RibXnAxRbvST+*?glNR)aIq(nY5*jm{WXm0fA-&sS@)1FM`Sxg|F-)9ZboDM7Ej z&e5@!g00ky;Nj9c9ta%39kvM2o$Dg!Ko0XVeKL7^Qab-%T2WNV^QS5Q}Pa@Np(uGI=htWfnRjPrPzb4_{x1ds8*GY zl`1AdBgeLSS)`>_mk8w9fZVW%a~J`R&x^Z!LTAVuKyM$;974PJ(#j_OgcP$z5vA&N zEWubq%|2RNQ z*6vPL4>(77w}7&J?gMBPk>lKAo&l$7fS$OlV4ma-FG%tLvZc7W=~(U1Wk5?u120XE z`pWFe#B2b^P-+YoUp*$Hw1x8~dFHof;v;8Ln~I z$+io|GA?ZZw+?j`n`#q(GNY|ZEN6V^>V~r8>@yHQmqTN;4Pz#-_V_^l3*xfAgOjo0 z+>%|3z}jRr{r|WykXn#O_lhqvCgj%0s0fAD?E#+ zD-zR;%b`9VG86hv>rfepTbk+tv29t_nk$Z#<;v*FAp5%Z#pSbiJ^pZeDdWnew4a_Q z*}sCSwf~V0`vQ+a{ewtMeaa2N4WNK*>@xyO&?+10zsTmE=5rUL@@!j2wO7f;6dr@u zp2@fE11>x)^X)gDH+Q&+$<3N`erN(KHfW9;f=^&oCMJal7LN4AbtoT{&P?dLDClAe zHY71s%9brXpgNIXQ>xwI8l$O^eYH3c;aW&^?YHUYEAcH#A${aHfNJ%VVK5oJRtiLjFa)@)=?rzNFwBn1cmzv`dHf%lt*4h4P6Wft zCCjigJcr{+m9If?oMj>TI?aIvPlVCWf$F@HT^)smlEGimWla^;UsrMpX*z=4C+pHO zoeDbIn&5wQw5}=6{DMo9>Q0#~rMh)&H+)!eF<4(LB9U?tLC$)CoWNmpe^9T%5K7jK zZ^vg?*iiG4O2TBb-6>&bLxHaViedATL6J1^+mH>&vMANxhyzjmAzEC70?m|puI(MK zkRHo;a^QPV>2HdySA5?cEZEpQ^E{(}Cu(G*xzndK)?y$1$>0Z@7lJ6x@LUGUh@T&+ zwAYs_xDpSFNaod!4g|6~fggZa`dksA<9b-3SS1X^F`@@2tpFUES zZyiZIFIm>YzgCF4qK8AfTvd7}X?}n%l_!jPv6bw@{7x~kc71XKdEl>?j|c{1mK5&M zt{?l|-jTTC{V9ZXco7177a@XQiLkf<16|2eqJ!0L2#Kl4E(ENxTkfs)HgKsuTK&-` z2wdLptvH|LTncDuC{)-lX0&1>lToabp}PP}(Cks#q$@P5M9j04m&|n)U@*DAT<5ww zEk52WEREY}klr+Uoc5>FE~&&q7Gl$kx%lQ#1!KQ84~(;6!LmEuTKz3uxPx zQj(Mm&7H!q%_CG?E6*UFfp9pzCMW0+4wi-(K$SEGJ%%ahMr)6LecwJcEIvnSC#nHt z8wi2i+bfJ@VzZ=uW`Fm1MHCg!?*1Q{W@Tx{ZAJj>GF)_c-a)f}DcgLUEQYdbM9?UE zbmrWa*6o&lF&<_LcRpP0x3_q=#>8~oeP z91J+KGfz`^N6?1hTI6};au6?)2(oEj#3es3NexUp6)c#>2=dJt+#c@kI1;xNh36fW z`PaYO3Wsj(Q>LM1-JhgaJON#$eTJC=o$4&B>Uz z+y(hTREo;0Di$?i&`E-35%+*QZPjL+8^}3Y_l%SApaz8*4R=;`2W&|UNeBu7H?p$J+rjp;Dv=`>4gwqtv6iI{dbePn9U{D$Ut--+)Cz;N#k5z3r365^;XkV<> zX9#PKZAC59B;Tb-aioy{`-RiUR@5X))QCWMtZiKW$rM!e_Q;@05;{--A+4a7R*gpg zYYVMS`pK%hAdl?lQ}R;2H$N8L{{s&Qk*z*TaARZ1`{X@3?QQ>?*VBH`g+}Y~e2U0z zF9eZ~&_Vs`@`I=_a{jn-#xv+;=}7V%LaEK*=X6-=6z=}KcpB_WLl3#FANzajB`GVM zg&1%L+$VPu#Gy(mB0j!G^l~|Uk2cif{Wpk-B?NFX8xYim-q{8RN6}r-gwM(5p{PnE zL1JbDCr=6SQu>EGz-gTWJ=}Knkc|D6d*8>br;FA6_M(cu28N`3L5LjXsh}O;k&A&; z6H&vAJ~Gb|RP~FmZy5(eAA6QEFvx!6Q*b}#P67JK*?a#A@T&KLW%;sb6V6P4o`*hS zD4v5f4TK91ay)fm0DT0SWQ&MTu86>ds~Nj*NWpV`Pk(&?+u0U)Ih%Qf9;hS5y9dQt zi{>t^&`)cv)_2xSVn-e3-C*C#Gm|(D6nf#z*Yq>M#W%D#1Y=%)XyIbLqb0QFJhTLj zc=gjx;Tp`DtXP=8q4^$HnQ9O;raHamhW&LA5*R{FNqBu=MWs~ssYqK42PgAePjB2s zp)S??Gx~=ks5W<_j+l+u^A5?9SJR+(#B@TbUH{yOY(PVnH(Zgs+^q0?y9`Z4E8UX>`+6?H;e z^Ky~&I7h%nfJu0<&+Y1`;k3g;rLlSTaqAhulZKtGM>@Hj#DupJI zOZ2DYqRtS+M(H&*CNW((>c15=0#e$1#O==q5nY^^=0$Ie z6?frEaabQT5Ce1C-O&NBk|#QQ>00Jv^|8XJJ?cH(DpP#{@Gwe@9W?;jXG5EM?_O`7 zBd<2i%f8^0dF)&ooV~*LJqZPqJj5l`t63K6oEAQNMns|u6xpL{v z9QYv>rD$ZuT4);Fu9LR@1jYt*OyrE&r5sueQHX_a^*E{-It!jp^EiY$EV#a0Y87xO zV>{!bexKma2JXG6i@hGlM(dk1$7R-*kiYvsZQA`1!HWXG2pCOOjp)iPl|&r-g9uR! z1lEFGQ<4gium)#A;}e8rj@x%tj44l7x|s?cLbZN8!-i`s-xw0e%y`=1*s6Ps$Zz4NNjwD)}Q!tn72cJ9PJ-0dFKc7Qpods1JpD^$}bweoLn>79@s{_+9%e zxD+BmAL|i&cTi)QNzJdskE)vW0(u)GsYk8(P$Ku!MWYDRrwP2P4g6Zh0W9G5Eh0x}a0q?#L@E>f!fhRu!vNbCd((Kj& z3!SHLDj`~HJ2Vg^LOZfCTAoGiHJ5CKzBVuY$=VtBhmo$R{-fi{4GJIpVA_;Y^itKp z3V#GM2?$ROf_|c+Y*BwHnBp#3!BQci=wJh%FnfyYL_B`ET%E;4#h&hR}7p_r7=F>(mkp{S`;P)XIYY@N;uKEadVdAZ5$ysa&7*+zwjE6Ge6fadACVR$H?0QiJ} zR` zR(in--U(Xs)g^3x&HyeyJvJDludjax!U*l2r{#+CkB>gmj2~}HekkoO#a7-!QX*PrR1 zLE1@Fuyp$DPR5i6LNetsKlowyzzY%%cQA%ft$!q*Pzh6#&p~th(IqW0hrs}^U3R7& zFB4P)d_O>_%48;jhioedIgwM7urGFY$5#0+IMSfU{UKG$bmE~mdxGcRco);0cL8Ui z>>Pq(e$n-mHzbzp-(N`$&&@_@wb=E1ut8>HP^}yhzm?DW!tL*Ln6Y&f`@HWHK*%Q@ zT4F*PPd|9;bjGz9w-@%Tco8w2JsE9-e282?YZNc|yy)-^b~3d;T6#4;7loSrC6ObN zv&-@|q;1cRm#NljsD^MwjTjA?{qtB!tA&Zc18lqb4l>}a63p#Er;4tCj#Z6?Wo(C! ztpglUq8V6CX?~;3LIPg<;$p@PO-|;Ys)7!QNvNQod+E1!FpyC!*H*KvwGw)-BaWI1 z!n?JM(^&$n>Rw%}7AJIJT#RM;8TW*~2Z)^Wg6Ujnb>^>M$q0n zSYk+(S6w!q2^9e|opv)~`cxvc`xKkKDo63DZO#iC*B$0#EA_7ya=$vxigPSom>EQS z4dPQ<^_Ltz~#i>FAO6n*ylQWZJ}qv0YAM>G0JboVQ>>dbaF5_oqOdXtOZ$J zD^BZ7%8DN|Xj8WW@q--!@4cb=Sj10ZeXImVq}7_sBo0y(Ph#n4%DyvCwVlYKGg!@oM zMR93I=s|PE@!-j{@ue+Q3raf~kA}0hnjUi0ulfau6_XgiGWj@IHrQ3ilB2zU=VO#R z8@d(mHF#ClF9xuv&~HkmI*;Y_M-(4LWk%2#ta*(5a-&9BC%BrwW9 zcKHzAPm22uxo!Bh^fCj^{DYF-hh@@(+6CU>g_PQ=-L)eM;C|lA7m|WgS%{W%B47H? zl5|{pB5JhaNIG5DOza{|R6dQzxD(YN4=GnGtF}80lJ#&VDX<*x zVjub*Y6^1jA8ms0(V9|EYNWoFb7ZFmTl8gzQdSA;ur`&b?GRqB7(Ta^(M>6}z` zDX+?jQ5RTgA_aFt?u%<-5{g}WgIS5uc|xe+I*ZdFe~MZo%ieXMmPqle%8s`xy*F2A z^uw;ZNXv5PNyw*u^jt@BT?JfmG-t$O<+azFp>lX7*vqbDmhp7Uv&qaH$GYT4?W#(T z*V&gzyK43N5!l5t`dOX94FxWPT;nD_^^lS*e}Csp-! z*){H1ZtqUD9W!%sjh|yN;Te2dS~Y2}(zk>MA>16}tmH2l%hY2z`1?I#i& z3Q`tO6Ez^>-tus$-re?q8G=RY8~yxfetyR5~;*Hb}Cs<4r#m98wG!iEEM$JFDj>(`B3%G#O@=d=Sk~4oQ^) z@1cLcy>n-r$D=d{<-V(IW@r8ql1hJe7!2C-zTLg!8Cy3{Al++x&EP(_kwd2a>WQow zuLn#KIp=ZII(4fE5$dF=pCZ;Sg zJ(z3kGOiW<;2kq!NDN&wRhjNLIPD@ty=iws<(QD6G;njd)|%v9*4b1FrzT5=O)gwl zJf^>NKoKqz^9G9qQ)GURMXYPWPDYl)+XwZwht>{SB|dXd7W05A1XiiJfvG7M19jLV zyLwd;;qb8LX65yDDFu~P^V7s%-K(pW3bIx-o>T0~bn&XljBH3RBrr&v35G(ZTdqQ1 zTDWB7$Cm9y1it+phZ8}sa;3L!t4Pg|tYdvss{qTscAJ5{T>XIeXd&j!N?K~$DF zkB4Nr|8rIbtd?vNYax1D#yG1*+>?%zC%}yHftM>NqZi6Ip8iKOl#zg?BZNv=q*Uf` z0~ev*8El#xhjeO+np|IlOYcTa>jbR&ro*nJboc1o%Ss=Nh!2>DiRwx1nh8ueZwb|~ z&Ig~(n?02eAujN3IkU`;q%Qv3&6`k0;Y`7o3q3SAH8??-`E4&23mE++~|MwxK(Ui2mv?F2O<+KBkD7*CYEaon?ib+ zo%wHv@RlJbPe@L2SzJC97F0~6+ZXwIfUmB8hWC(NaC%p;1{`3gc|=w{iT?k{aS zyB+l|o;$JXpk``p+C$g{5A7QWia!vpdejEehV6Y!qhp^`YCuet?7ECA9?7202kXuy zD+FKu+GJ%`x7OawDELu-*UI#cB#2hi9fGZCeW_>0IEMwXZb43>lCeF^x@`g+Y%daE z-_TpXO2%NRgRU)Ph=UjI%F4|qZ55G=6Lw8s>~4Rp6+q4zYu` zU+b7HU@MJU>{Gs=j#F#Hf*_PKu>#5-xqI{dUyMVV!!n(uNkfy>ObP|wY$65>RI@m)jXx`I1vGdZzgCeNmjxFpeXU| z;Q95jBQ%3|BU+RFDo7e`Kku?&HMS&2S{)Sc__c2Pp7whktCeC{kRN-X-nOnbLenR+ z*~Aqm&3z0d&2DnT3zp~FNpBu9ws%3Lj(eygWIi~1t$rop^o3t@H|KC&zmEBOyHuY+ z)a!dQZ?z+$X1E~6&~dzbu5+EI>ECR}?t7m)-T+>d`*ATe{kswLqc!d!C!92U!G7_! zLKc+R^31S+(zuUQh!A!CRC>jARR8VHCbOl(K>wXy2Ad4FcJ$i8dOpKhKy}>t#Jf1k z-q3q>stN4E2b)!L$6>Cz;`@0p`?2CQT1rYKJ6y@JNKnXQ7UXy)#k8J{>oCf4YM6_& zc;9y=jN#~4jpdRNosQ`beP>+h+&3aD)uN&OM_^>!R<8bK8ZF(R;0s^e@ z>Oi_9eiF@bPG8V~n&5oL!|hnQ#h>mUf5f zm}P&pp6n&bT$NmQQ(3_%%hB0Bmzo}P#hw+t(?|Kzw$YnC}H{u0Ra@*69Jdy^@KF>aBX_p*(zKQh9B z+i1rL6Q{#GGmx-5brPo|A@rN+XI>TL z9%LxYkvOXZ33~jxmsqX&`I#-23v*KF>mX9zRdqqEj+uR61>WIz5gg{ zycEN_wWq9AjBmAjoiVthTD6Bj+Zq<2sorc?eV=3+TIG)dqx+5T@%qAn7Thqq`IV_m z>>UWHKhtUxeUhJ}Rs);;)37eySS^$3)SzH4L>AQ-oN$W1xx13?)hdZD-_(IMQnJ+w zoZyYf3D{c;A;2EzbVH>8_jqd#gpxfU?B*EC8?Z*eCGMkwEX#x2(<0k@duFw0??SY=4lo+RApfDZz7aNFNhAhT6BkC1&X}ObsBU z=@5?Ed>N3J{@AfN$$5mI81vn2TnY-rYbiSH~D2DMbpEyP*9-WP3 zS474(XE#RXzD*4{wipsWA8uKbAS=QFe?@mQAzH3(Q>#;n#&14BLQ#!7yXE5+_~akz z*|swNiR&YCcN1_-AxbAc*nvRl#P~XEe@*(vwws$y^Ui<^>qw_zQQVk2ja*Z$(=HOV zL-tzBLa&KOOGR?$V16KdsHQu!W+NP)Ov`s@gdoR0$SB~$g+U;9MgqX@{X9|XI2MS5A|1f+K`6dT#uZYHJJB{ zB=N&{(w63uUerF}L)WfWRP|V}Dw;dv;KE@5fj{KgJWNcjNWDAyRXSzAQkXtEj~XG@4l~vgNntR>C2AC z641s!3JyGnih)`PjeO|b{Ru8Gn94ba9=Q^VDe_-|a^}BQL*$i^&AwL=u3{(iU~fMT zfQJ8%enbCvP_R5NZxRk1M-*dxEX56Ohf`6=6Z#8KKM$$yBIM8$0jYWGt0WLI0hc*~ z{6@(|CO<;Z5t@&a+QH!9EN*ULj{j#6o5W2FTgaVYWJUaWRsP4Ge=Xr$mE~rE;lx&$ z0VIB6@?U}ko-jGmnO0E@G+%_2wTQW@i1tU0#}&` znk!{D{ILaDk;vE3gZv+%zqjj^?8)qzoamj*Gyxz=$0G1EYJo-D%@B?ClM3NjSsKSGt3_tS+A4+p8fuK(zN*v1esS$&*Bj;8n2DEU8gSa(x5T&~7 zPC=;146+?plYWK@LuB@p$jky%!0vH_O}?qbzk-gHbc)@^qJI1&5s?QMEMkAroHmsM z2{!K=z5pelsa4^RuDFJ%?=+ZAghWatR*@5-6=2-}4122V2cp;js9>_LMUs(u)bW6r zWm%KSjnB^BrbW-^A1r(G$5L?-(L5XroSK)?za=$ID8;Jdu3@1wP$<7=MPucci%Z-v{^< zu`#VEC;sHemW3nV30e!(qU^{TB#16&6F%YQqOG+1((dqeaMtoNHUd(Z0jP5;rdLY@ zu<$Qi#r(CM?bil(^xgl#@PB$b(^lh6155_nzO%99Kw)pD7GlW8TTnE940X03u)aX< zJL|a!;*n1A8aGY`834J^B9YcgJ%t{R%GLsheJ4 z3&{Udlc{fNxZ_^-ceHCg_Hnr#jN}+*+zyaD^du~Zz7GTvi#!_qE`h)Q&Xv}0KjyEn z9H?D`D4uJic(}Za<_>XsP|1`)a(O3G_(6V3Z#pqL+K-OU0=@ap$~pK|Hix5V#{)JK z6M=tWD1oah+~G(E6x&i}x%D+^!JX+LSQbR!Wv+fq(TxAQR!+4JEdTjsu8#ib3+g#6 zWfP`z#bRotT+JI+1A#%P8^bSv=1o!i2B!A(@07^Elvn~(ni5J(Snfb%*oD`#E$6BR zWY38D2?!ir3&=cUj31-{v8JTV3=71ZAKaRYyX)&>*d@x5H)3`>aOuPLfXj~VVCqlx z>2&wILEtt?!3c+>uKuCU|J>rAB4APD?2C{y=CZa}P)U z8#Qs9l6k-5l4<+CjlsO7N{Pacu(R!4V!0hZ;w25U2?L6J0F8e6`E+aA*7=AcrPCMj zoQTG6-GjbbKA#2#)vf2tKT4&>en6v(+|ncKK`+2qBIzR4B}dH3Q6GsY?}xHT7v(YR z-<)Z2d9?VcFk_pM7y_Db)uq!&{V_I^zd9ZMB~{&uP%~L*tjc z8y73UsJOUZ+W0j%RI+O(twaLkgQ6Bdq|q?%{1@pKI}4UAE_q29P-y!sZv>kIC5&QB zxw@_de*UCC^`pi&lF`nLzX`qF`=v=$ZFV%@@Gt@Oi3m!c2TD*@jK~F>btOL=EJ1gk zkNX}tDaeOhS7OoJN%!HjE&YU4D{logw|-au4-ZedXtvFxnAv7!;P$8N^HI93Mjer7 z$Ln!l+VwPZ0>hGv=xwjCSqsAn74pQSZdIf2GiO}t6Q`TRg6!@d9#m>GIjqDL^c+z( zou9uT6+3NoZ!%+m+S-E5AzGtzD!nCIW zSUb~w)JN%&{^)7T)5J#nxGI(;E?9y!({+s(;Qe&*m}4%swHLfx&cAwMS|&%L)J636 zY^a=u3Sizq=tHoiZ@=6;-8TdY+bC<+_t7A^_bnk>RlRYd;!LNSr04v+LIoan5LUV7?$NO6p=B6q=RsmO?!Le%tG1k1Ot$%a(>5w$i;BW zDtE==V%J=(@S){I3bl{VB2uyfAy*-cj*ES;PygoOoTlO`&w{rP`|s2PRt?ihR_!ny zqQfp$16E!G`$YJX4@K5Jy-SGNzi2u-47Mh@kd%&&7v(fn%2NxjJGs%tN1t8&!h?i^7=_cmw;xFfcm`@gh48P3mNSenJ0^fh4fjMg{3Sup_X zrVLEXM;{ZR0E*HVVb$j?hFW)lL@nG|tChW~C;05p;2^8y1JU)G?h+~uTJx=(nmp9#U1F!<9?cUR`@9Cobi0>8k8+ zzU41>6cA#E0I$&5p0fq5FVOS#k4vn6nLlj&jt)TARoEhln}v#5c+F~F++`TM;pM2~ zC~L3(MGC%ydIAOe*!R5(0n)hWq|Bz z?ictjvK^?3Ka~AgituMTR#y1*9P3>(wT!^u{<1~*O{9A=-QcCF?Da|k{HWemL+#|v H`vd+DXhb<; literal 0 HcmV?d00001 diff --git a/design/one-pager-generic-usage-type.md b/design/one-pager-generic-usage-type.md index ed9e3466d..cf7d948cc 100644 --- a/design/one-pager-generic-usage-type.md +++ b/design/one-pager-generic-usage-type.md @@ -99,16 +99,18 @@ metadata: name: release-uses-cluster spec: of: - - apiVersion: eks.upbound.io/v1beta1 + apiVersion: eks.upbound.io/v1beta1 kind: Cluster - name: my-cluster + resourceRef: + name: my-cluster by: apiVersion: helm.crossplane.io/v1beta1 kind: Release - name: my-prometheus-chart + resourceRef: + name: my-prometheus-chart ``` -The `spec.by` field will define the resource that will be using the resources +The `spec.by` field will define the resource that will be using the resource defined in `spec.of`. Both will support only cluster-scoped resources, namely `Composites` and `Managed Resources`. @@ -127,26 +129,21 @@ metadata: name: release-uses-cluster spec: of: - - apiVersion: eks.upbound.io/v1beta1 + apiVersion: eks.upbound.io/v1beta1 kind: Cluster - selector: + resourceSelector: matchControllerRef: true matchLabels: foo: bar by: apiVersion: helm.crossplane.io/v1beta1 kind: Release - selector: + resourceSelector: matchControllerRef: true matchLabels: baz: qux ``` -While the well-known use cases for this feature are solved with a one-to-one -usage relationship, we will support one-to-many relationship -(i.e. `spec.of` as a list) as well, considering it provides more flexibility -without introducing additional complexity to the implementation. - ### Implementation The implementation of this feature will be done in two parts: @@ -165,19 +162,68 @@ relationship by: - Resolving selectors, if any. - Adding owner reference from the using resource (i.e., `spec.by`) to the `Usage`. +- Adding/removing owner reference from the `Usage` resource to the used resource (i.e., `spec.of`). - Preventing deletion of `Usage` before the using resource is deleted. -- Adding or removing admission webhook rules to intercept the `DELETE` requests - for the used resource(s). +- Adding/removing `crossplane.io/in-use: true` label to ensure the `DELETE` + request intercepted by matching the selector in admission webhook rule. **Resolving selectors:** -The API will support defining selectors for both the using and used resources. +The API will support defining selectors for both the using and used resource. Initially, we will only support resolving references with the following rules: - Resolution will be made once when the `Usage` is created. - If multiple resources match the selector, a random one will be selected. +Once selectors are resolved, the controller will fill `resourceRef.name`. + +Example: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: Usage +metadata: + name: release-uses-clusters +spec: + of: + apiVersion: eks.upbound.io/v1beta1 + kind: Cluster + resourceSelector: + matchControllerRef: true + matchLabels: + foo: bar + by: + apiVersion: helm.crossplane.io/v1beta1 + kind: Release + resourceRef: + name: my-prometheus-chart +``` + +to: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: Usage +metadata: + name: release-uses-clusters +spec: + of: + apiVersion: eks.upbound.io/v1beta1 + kind: Cluster + resourceRef: # added by the controller based on the selectors + name: my-cluster # added by the controller based on the selectors + resourceSelector: + matchControllerRef: true + matchLabels: + foo: bar + by: + apiVersion: helm.crossplane.io/v1beta1 + kind: Release + resourceRef: + name: my-prometheus-chart +``` + The [existing policies] for resolving Managed Resource references does not necessarily apply to the `Usage`. For example, supporting an `optional` reference while defining a usage relationship does not make sense. Also, the @@ -186,11 +232,20 @@ the `Usage`. However, depending on the feedback, we may consider supporting resolve policies to configure whether the resolution should be made once or continuously in a future iteration. -**Adding owner reference:** +**Owner references:** We want the `Usage` to be deleted when the using resource is deleted. This will be achieved by adding an owner reference from the using resource to the `Usage`. +Another owner reference will be added from the `Usage` to the used resource to +prevent Garbage Collector from attempting to attempt to delete the used resource +before the `Usage` is deleted. This is mostly a mitigation for the case where +deletion process of composites, which rely on GC, could take too long because of +the exponential backoff in the Garbage Collector as a result of failed DELETE +API calls. + +

+ **Preventing early deletion of the `Usage`:** Typically, we expect a `Usage` resource to be defined as part of the same @@ -199,13 +254,30 @@ the delete request when the composite resource is deleted. In this case, the controller will prevent the deletion of the `Usage` until the using resource is deleted with the help of a finalizer. -**Defining admission webhook rules:** +**Adding/removing `crossplane.io/in-use: true` label:** The admission webhook will intercept the `DELETE` requests for the used -resource(s). To achieve this, the controller will add [webhook rules] for the -used resource(s) when a `Usage` is created. It is also the controller's job to -remove these rules when the `Usage` is deleted, and no other `Usage` resources -reference the same used resource(s). +resources with the following admission webhook rule: + +```yaml +webhooks: +- name: nousages.apiextensions.crossplane.io + objectSelector: + matchLabels: + crossplane.io/in-use: true + rules: + - operations: ["DELETE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" +``` + +To ensure any delete request is intercepted by our webhook for a resource that +is in use, the controller will add the `crossplane.io/in-use: true` label to the +used resource when a `Usage` is created. It is also the controller's job to +remove this labels when the `Usage` is deleted, and no other `Usage` resources +reference the same used resource. #### Admission Webhook @@ -292,15 +364,6 @@ will be blocked until all Composed Resources are deleted as before. It will take longer because deletion of the used resource will be blocked until the used resource hence `Usage` is deleted. -> One caveat with the garbage collector is the substantial delay it can cause -during the deletion of composites. This delay caused by the garbage collector's -use of an exponential backoff when the DELETE API call is rejected. The maximum -backoff time is 1000 seconds, which means that after no usage of an object is -left, it could take up to 1000 seconds before the garbage collector attempts to -delete the resource that was previously blocked. To mitigate this issue, we -could introduce a mechanism in the controller to re-trigger the deletion of the -used resource as soon as the Usage resource is deleted. - #### Directly Deleting a Composite or Managed Resource that is in Use When trying to delete a Composite or managed resource directly, users will get From 7f18618c0685572767b1285e966c9745850fe8fb Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Fri, 14 Jul 2023 15:43:38 +0200 Subject: [PATCH 085/148] avoid hard-coding registry endpoint for image copying Introduced funcs.ServiceIngressEndPoint(...) that return the endpoint that can be used for accessing a service deployed in the cluster. If the tests are running against kind cluster, it consults the kind config and if particular port forwarding exists for given node port, it returns the endpoint accessible from host interfaces. Otherwise, it tries to detect node ip and use the obtained address and the nodeport to access the service. Signed-off-by: Predrag Knezevic --- go.mod | 1 + go.sum | 11 +++++ test/e2e/funcs/env.go | 110 ++++++++++++++++++++++++++++++++++++++++++ test/e2e/main_test.go | 2 +- test/e2e/xfn_test.go | 28 ++--------- 5 files changed, 127 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index ea2f3bb28..94d7449e9 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( sigs.k8s.io/controller-runtime v0.15.0 sigs.k8s.io/controller-tools v0.12.0 sigs.k8s.io/e2e-framework v0.2.0 + sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index 47a6cd29a..a5aaf13a8 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,7 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -83,6 +84,7 @@ github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2o github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -148,6 +150,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -316,6 +319,7 @@ github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8I github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -359,6 +363,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 h1:2uT3aivO7NVpUPGcQX7RbHijHMyWix/yCnIrCWc+5co= @@ -401,6 +406,7 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -437,6 +443,7 @@ github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0 github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runtime-spec v1.1.0-rc.3.0.20230610073135-48415de180cf h1:AGnwZS8lmjGxN2/XlzORiYESAk7HOlE3XI37uhIP9Vw= github.com/opencontainers/runtime-spec v1.1.0-rc.3.0.20230610073135-48415de180cf/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -473,6 +480,7 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -695,6 +703,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -963,6 +972,8 @@ sigs.k8s.io/e2e-framework v0.2.0 h1:gD6AWWAHFcHibI69E9TgkNFhh0mVwWtRCHy2RU057jQ= sigs.k8s.io/e2e-framework v0.2.0/go.mod h1:E6JXj/V4PIlb95jsn2WrNKG+Shb45xaaI7C0+BH4PL8= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= +sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/test/e2e/funcs/env.go b/test/e2e/funcs/env.go index 78330a5a9..363f4199f 100644 --- a/test/e2e/funcs/env.go +++ b/test/e2e/funcs/env.go @@ -18,12 +18,19 @@ package funcs import ( "context" + "fmt" + "os" + "path/filepath" "testing" + corev1 "k8s.io/api/core/v1" "sigs.k8s.io/e2e-framework/pkg/env" "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" "sigs.k8s.io/e2e-framework/pkg/features" "sigs.k8s.io/e2e-framework/third_party/helm" + "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + "sigs.k8s.io/yaml" "github.com/crossplane/crossplane-runtime/pkg/errors" @@ -32,6 +39,8 @@ import ( secretsv1alpha1 "github.com/crossplane/crossplane/apis/secrets/v1alpha1" ) +type kindConfigContextKey string + // HelmRepo manages a Helm repo. func HelmRepo(o ...helm.Option) env.Func { return func(ctx context.Context, c *envconf.Config) (context.Context, error) { @@ -102,3 +111,104 @@ func EnvFuncs(fns ...env.Func) env.Func { return ctx, nil } } + +// CreateKindClusterWithConfig create kind cluster of the given name according to +// configuration referred via configFilePath. +// The configuration is placed in test context afterward +func CreateKindClusterWithConfig(clusterName, configFilePath string) env.Func { + return EnvFuncs( + envfuncs.CreateKindClusterWithConfig(clusterName, "\"\"", configFilePath), + func(ctx context.Context, config *envconf.Config) (context.Context, error) { + b, err := os.ReadFile(filepath.Clean(configFilePath)) + if err != nil { + return ctx, err + } + cfg := &v1alpha4.Cluster{} + err = yaml.Unmarshal(b, cfg) + if err != nil { + return ctx, err + } + return context.WithValue(ctx, kindConfigContextKey(clusterName), cfg), nil + }, + ) +} + +// ServiceIngressEndPoint returns endpoint (addr:port) that can be used for accessing +// the service in the cluster with the given name. +func ServiceIngressEndPoint(ctx context.Context, cfg *envconf.Config, clusterName, namespace, serviceName string) (string, error) { + _, found := envfuncs.GetKindClusterFromContext(ctx, clusterName) + client := cfg.Client() + service := &corev1.Service{} + err := client.Resources().Get(ctx, serviceName, namespace, service) + if err != nil { + return "", err + } + + var nodePort int32 + for _, p := range service.Spec.Ports { + if p.NodePort != 0 { + nodePort = p.NodePort + break + } + } + if nodePort == 0 { + return "", errors.Errorf("No nodePort found for service %s/%s at cluster %s", namespace, serviceName, clusterName) + } + if found { + kindCfg, err := kindConfig(ctx, clusterName) + if err != nil { + return "", err + } + hostPort, err := findHostPort(kindCfg, nodePort) + if err != nil { + return "", err + } + return fmt.Sprintf("localhost:%v", hostPort), nil + } + nodes := &corev1.NodeList{} + if err := client.Resources().List(ctx, nodes); err != nil { + return "", errors.Wrap(err, "cannot list nodes") + } + addr, err := findAnyNodeIPAddress(nodes) + if err != nil { + return "", err + } + return fmt.Sprintf("%s:%v", addr, nodePort), nil +} + +func kindConfig(ctx context.Context, clusterName string) (*v1alpha4.Cluster, error) { + v := ctx.Value(kindConfigContextKey(clusterName)) + if v == nil { + return nil, errors.Errorf("No kind config found in context for cluster %s", clusterName) + } + kindCfg, ok := v.(*v1alpha4.Cluster) + if !ok { + return nil, errors.Errorf("kind config is not of type v1alpha4.Cluster for clustername %s", clusterName) + } + return kindCfg, nil +} + +func findAnyNodeIPAddress(nodes *corev1.NodeList) (string, error) { + if len(nodes.Items) == 0 { + return "", errors.New("no nodes in the cluster") + } + for _, a := range nodes.Items[0].Status.Addresses { + if a.Type == corev1.NodeInternalIP { + return a.Address, nil + } + } + return "", errors.Errorf("no ip address found for nodes: %v", nodes) +} + +func findHostPort(kindCfg *v1alpha4.Cluster, containerPort int32) (int32, error) { + for _, n := range kindCfg.Nodes { + if n.Role == v1alpha4.ControlPlaneRole { + for _, pm := range n.ExtraPortMappings { + if pm.ContainerPort == containerPort { + return pm.HostPort, nil + } + } + } + } + return 0, errors.Errorf("No host port found in kind config for container port: %v", containerPort) +} diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 155e419f1..a9464975f 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -154,7 +154,7 @@ func TestMain(m *testing.M) { os.Exit(1) } setup = []env.Func{ - envfuncs.CreateKindClusterWithConfig(clusterName, "\"\"", kindCfg), + funcs.CreateKindClusterWithConfig(clusterName, kindCfg), } } else { cfg.WithKubeconfigFile(conf.ResolveKubeConfigFile()) diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 368e955df..5f5984c53 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -106,31 +106,11 @@ func TestXfnRunnerImagePull(t *testing.T) { ))), ). WithSetup("CopyFnImageToRegistry", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - var reg string - _, found := envfuncs.GetKindClusterFromContext(ctx, clusterName) - if found { - reg = "localhost:3000" - t.Logf("Running tests against kind cluster, container registry accessible from host via %s", reg) - } else { - nodes := &corev1.NodeList{} - if err := config.Client().Resources().List(ctx, nodes); err != nil { - t.Fatal("cannot list nodes", err) - } - if len(nodes.Items) == 0 { - t.Fatalf("no nodes in the cluster") - } - var addr string - for _, a := range nodes.Items[0].Status.Addresses { - if a.Type == corev1.NodeInternalIP { - addr = a.Address - break - } - } - if addr == "" { - t.Fatalf("no nodes with private address") - } - reg = fmt.Sprintf("%s:32000", addr) + reg, err := funcs.ServiceIngressEndPoint(ctx, config, clusterName, "reg", "private-docker-registry") + if err != nil { + t.Fatal(err) } + t.Logf("registry endpoint %s", reg) srcRef, err := name.ParseReference("crossplane-e2e/fn-labelizer:latest") if err != nil { t.Fatal(err) From 0efc33f88def6eeae44c5028207d173e6addae9b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:03:34 +0000 Subject: [PATCH 086/148] Update github/codeql-action digest to 489225d --- .github/workflows/ci.yml | 4 ++-- .github/workflows/scan.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c6ba4d7b..1131f72dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,12 @@ jobs: run: make vendor vendor.check - name: Initialize CodeQL - uses: github/codeql-action/init@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2 + uses: github/codeql-action/init@489225d82a57396c6f426a40e66d461b16b3461d # v2 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2 + uses: github/codeql-action/analyze@489225d82a57396c6f426a40e66d461b16b3461d # v2 trivy-scan-fs: runs-on: ubuntu-22.04 diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml index 26b6e2fbb..788497e57 100644 --- a/.github/workflows/scan.yaml +++ b/.github/workflows/scan.yaml @@ -131,7 +131,7 @@ jobs: retention-days: 3 - name: Upload Trivy Scan Results To GitHub Security Tab - uses: github/codeql-action/upload-sarif@46ed16ded91731b2df79a2893d3aea8e9f03b5c4 # v2 + uses: github/codeql-action/upload-sarif@489225d82a57396c6f426a40e66d461b16b3461d # v2 with: sarif_file: 'trivy-results.sarif' category: ${{ matrix.image }}:${{ env.tag }} From dc46a4648fd91cdc8840450b89c1fc721faab041 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Sun, 16 Jul 2023 20:19:37 +0200 Subject: [PATCH 087/148] ci: switch deprecated set-output to new format Signed-off-by: Philippe Scorsolini --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1131f72dd..e1ef44779 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,7 +138,7 @@ jobs: - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT - name: Cache the Go Build Cache uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3 @@ -206,7 +206,7 @@ jobs: - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT - name: Cache the Go Build Cache uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3 @@ -269,7 +269,7 @@ jobs: - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT - name: Cache the Go Build Cache uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3 @@ -331,7 +331,7 @@ jobs: - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cache=$(make go.cachedir)" >> $GITHUB_OUTPUT - name: Cache the Go Build Cache uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3 From 6377253e58a772d7b8b0f366283e33c4d9a7d415 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 00:06:43 +0000 Subject: [PATCH 088/148] Update debian:bookworm-slim Docker digest to 9bd077d --- cluster/images/xfn/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/images/xfn/Dockerfile b/cluster/images/xfn/Dockerfile index 47325069d..16dfce7ac 100644 --- a/cluster/images/xfn/Dockerfile +++ b/cluster/images/xfn/Dockerfile @@ -1,5 +1,5 @@ # This is debian:bookworm-slim (i.e. Debian 12, testing) -FROM debian:bookworm-slim@sha256:d8f9d38c21495b04d1cca99805fbb383856e19794265684019bf193c3b7d67f9 +FROM debian:bookworm-slim@sha256:9bd077d2f77c754f4f7f5ee9e6ded9ff1dff92c6dce877754da21b917c122c77 ARG TARGETOS ARG TARGETARCH From 63c92ac9a691ae1cd89718f929c1ffbc2abf2f98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jul 2023 00:06:49 +0000 Subject: [PATCH 089/148] Update mikefarah/yq Docker tag to v4.34.2 --- test/e2e/testdata/images/labelizer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/testdata/images/labelizer/Dockerfile b/test/e2e/testdata/images/labelizer/Dockerfile index a399088f0..18ca61c70 100644 --- a/test/e2e/testdata/images/labelizer/Dockerfile +++ b/test/e2e/testdata/images/labelizer/Dockerfile @@ -1,4 +1,4 @@ -FROM mikefarah/yq:4.34.1 +FROM mikefarah/yq:4.34.2 COPY labelizer.sh /bin USER root From 1271e775c925babaabf0fd9979692d32a12ff2cf Mon Sep 17 00:00:00 2001 From: Hasan Turken Date: Mon, 17 Jul 2023 10:10:51 +0300 Subject: [PATCH 090/148] Add reason to the Usage API Signed-off-by: Hasan Turken --- design/one-pager-generic-usage-type.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/design/one-pager-generic-usage-type.md b/design/one-pager-generic-usage-type.md index cf7d948cc..19d6f2680 100644 --- a/design/one-pager-generic-usage-type.md +++ b/design/one-pager-generic-usage-type.md @@ -98,11 +98,20 @@ kind: Usage metadata: name: release-uses-cluster spec: + # Reason is optional when this Usage defines a "Dependency" type relationship, + # i.e. when the `spec.by` field is defined. + # It is required when the Usage is meant to be used for "Protection" purposes, + # i.e. when the `spec.by` is NOT defined. + reason: "Release uses Cluster" + # Reference to the resource that is being used. of: apiVersion: eks.upbound.io/v1beta1 kind: Cluster resourceRef: name: my-cluster + # Reference to the resource that is using the other resource. + # This field is optional and can be omitted when the Usage is meant to be used + # for "Protection" purposes. by: apiVersion: helm.crossplane.io/v1beta1 kind: Release @@ -144,6 +153,22 @@ spec: baz: qux ``` +Another use case for `Usage` is to protect a resource from being deleted without +necessarily being used by another resource. For example, a `Usage` that will +prevent the deletion of a database instance could be defined as follows: + +```yaml +apiVersion: crossplane.io/v1 +kind: Usage +spec: + reason: "Production Database - should never be deleted" + of: + apiVersion: rds.aws.upbound.io/v1beta1 + kind: Instance + resourceRef: + name: my-cluster +``` + ### Implementation The implementation of this feature will be done in two parts: From fdcb0bb57a5add23fdd2b2752c8249ae57b951ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 05:40:30 +0000 Subject: [PATCH 091/148] Update module github.com/crossplane/crossplane-runtime to v0.20.0 --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4a9dd46c9..6afa5e03d 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 github.com/bufbuild/buf v1.24.0 - github.com/crossplane/crossplane-runtime v0.20.0-rc.0.0.20230622044456-2dfb8bc6bfbc + github.com/crossplane/crossplane-runtime v0.20.0 github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 github.com/google/go-containerregistry v0.15.2 @@ -32,7 +32,7 @@ require ( k8s.io/utils v0.0.0-20230505201702-9f6742963106 kernel.org/pub/linux/libs/security/libcap/cap v1.2.69 sigs.k8s.io/controller-runtime v0.15.0 - sigs.k8s.io/controller-tools v0.12.0 + sigs.k8s.io/controller-tools v0.12.1 sigs.k8s.io/e2e-framework v0.2.0 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.3.0 diff --git a/go.sum b/go.sum index bc68d756d..97cb8ee63 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/crossplane/crossplane-runtime v0.20.0-rc.0.0.20230622044456-2dfb8bc6bfbc h1:GGAiSNI47xNpWdO09+E0bZtpJIZMof9U8ZvTymq9S+c= -github.com/crossplane/crossplane-runtime v0.20.0-rc.0.0.20230622044456-2dfb8bc6bfbc/go.mod h1:XYUuhLfBtc7Nl1nHguPQQf6D4Xcm3idyIJ8+roe8Od4= +github.com/crossplane/crossplane-runtime v0.20.0 h1:MlPNrK6ELKLQdeHaIdKxQpZW2LSivSYXxHKVfU32auU= +github.com/crossplane/crossplane-runtime v0.20.0/go.mod h1:FuKIC8Mg8hE2gIAMyf2wCPkxkFPz+VnMQiYWBq1/p5A= github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= @@ -966,8 +966,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= -sigs.k8s.io/controller-tools v0.12.0 h1:TY6CGE6+6hzO7hhJFte65ud3cFmmZW947jajXkuDfBw= -sigs.k8s.io/controller-tools v0.12.0/go.mod h1:rXlpTfFHZMpZA8aGq9ejArgZiieHd+fkk/fTatY8A2M= +sigs.k8s.io/controller-tools v0.12.1 h1:GyQqxzH5wksa4n3YDIJdJJOopztR5VDM+7qsyg5yE4U= +sigs.k8s.io/controller-tools v0.12.1/go.mod h1:rXlpTfFHZMpZA8aGq9ejArgZiieHd+fkk/fTatY8A2M= sigs.k8s.io/e2e-framework v0.2.0 h1:gD6AWWAHFcHibI69E9TgkNFhh0mVwWtRCHy2RU057jQ= sigs.k8s.io/e2e-framework v0.2.0/go.mod h1:E6JXj/V4PIlb95jsn2WrNKG+Shb45xaaI7C0+BH4PL8= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= From 885c1cf6b688718d2269b337d7fae31eecb9706f Mon Sep 17 00:00:00 2001 From: lsviben Date: Wed, 19 Jul 2023 07:59:49 +0200 Subject: [PATCH 092/148] run make generate Signed-off-by: lsviben --- ...plane.io_compositeresourcedefinitions.yaml | 2 +- ...ns.crossplane.io_compositionrevisions.yaml | 10 +++- ...extensions.crossplane.io_compositions.yaml | 2 +- ...ions.crossplane.io_environmentconfigs.yaml | 2 +- ....crossplane.io_configurationrevisions.yaml | 2 +- .../pkg.crossplane.io_configurations.yaml | 2 +- .../pkg.crossplane.io_controllerconfigs.yaml | 47 +++++++++++++++++-- cluster/crds/pkg.crossplane.io_locks.yaml | 2 +- .../pkg.crossplane.io_providerrevisions.yaml | 2 +- cluster/crds/pkg.crossplane.io_providers.yaml | 2 +- .../secrets.crossplane.io_storeconfigs.yaml | 2 +- ...meta.pkg.crossplane.io_configurations.yaml | 2 +- .../meta.pkg.crossplane.io_functions.yaml | 2 +- .../meta.pkg.crossplane.io_providers.yaml | 2 +- 14 files changed, 63 insertions(+), 18 deletions(-) diff --git a/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml b/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml index 8c0ecfe33..99e5e0e0c 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositeresourcedefinitions.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: compositeresourcedefinitions.apiextensions.crossplane.io spec: group: apiextensions.crossplane.io diff --git a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml index 77e2007a1..9de2b4e82 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: compositionrevisions.apiextensions.crossplane.io spec: group: apiextensions.crossplane.io @@ -1956,11 +1956,15 @@ spec: list. properties: resolution: + default: Required description: Resolution specifies whether resolution of this reference is required. The default is 'Required', which means the reconcile will fail if the reference cannot be resolved. 'Optional' means this reference will be a no-op if it cannot be resolved. + enum: + - Required + - Optional type: string resolve: description: Resolve specifies when this reference should @@ -1968,6 +1972,9 @@ spec: to resolve the reference only when the corresponding field is not present. Use 'Always' to resolve the reference on every reconcile. + enum: + - Always + - IfNotPresent type: string type: object type: object @@ -2020,6 +2027,7 @@ spec: uid?' type: string type: object + x-kubernetes-map-type: atomic type: array network: description: Network configuration for the Composition Function. diff --git a/cluster/crds/apiextensions.crossplane.io_compositions.yaml b/cluster/crds/apiextensions.crossplane.io_compositions.yaml index 9347d9c2f..18af910dd 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositions.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: compositions.apiextensions.crossplane.io spec: group: apiextensions.crossplane.io diff --git a/cluster/crds/apiextensions.crossplane.io_environmentconfigs.yaml b/cluster/crds/apiextensions.crossplane.io_environmentconfigs.yaml index 2b8e17fed..3884d62c2 100644 --- a/cluster/crds/apiextensions.crossplane.io_environmentconfigs.yaml +++ b/cluster/crds/apiextensions.crossplane.io_environmentconfigs.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: environmentconfigs.apiextensions.crossplane.io spec: group: apiextensions.crossplane.io diff --git a/cluster/crds/pkg.crossplane.io_configurationrevisions.yaml b/cluster/crds/pkg.crossplane.io_configurationrevisions.yaml index 41b5dfe7c..1291804fd 100644 --- a/cluster/crds/pkg.crossplane.io_configurationrevisions.yaml +++ b/cluster/crds/pkg.crossplane.io_configurationrevisions.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: configurationrevisions.pkg.crossplane.io spec: group: pkg.crossplane.io diff --git a/cluster/crds/pkg.crossplane.io_configurations.yaml b/cluster/crds/pkg.crossplane.io_configurations.yaml index 1b98b1c87..6817f8956 100644 --- a/cluster/crds/pkg.crossplane.io_configurations.yaml +++ b/cluster/crds/pkg.crossplane.io_configurations.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: configurations.pkg.crossplane.io spec: group: pkg.crossplane.io diff --git a/cluster/crds/pkg.crossplane.io_controllerconfigs.yaml b/cluster/crds/pkg.crossplane.io_controllerconfigs.yaml index 144446e17..6810e70ee 100644 --- a/cluster/crds/pkg.crossplane.io_controllerconfigs.yaml +++ b/cluster/crds/pkg.crossplane.io_controllerconfigs.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: controllerconfigs.pkg.crossplane.io spec: group: pkg.crossplane.io @@ -148,6 +148,7 @@ spec: type: object type: array type: object + x-kubernetes-map-type: atomic weight: description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. @@ -248,10 +249,12 @@ spec: type: object type: array type: object + x-kubernetes-map-type: atomic type: array required: - nodeSelectorTerms type: object + x-kubernetes-map-type: atomic type: object podAffinity: description: Describes pod affinity scheduling rules (e.g. co-locate @@ -328,6 +331,7 @@ spec: The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: description: A label query over the set of namespaces that the term applies to. The term is applied @@ -384,6 +388,7 @@ spec: The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: description: namespaces specifies a static list of namespace names that the term applies to. The @@ -482,6 +487,7 @@ spec: requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: description: A label query over the set of namespaces that the term applies to. The term is applied to the @@ -533,6 +539,7 @@ spec: requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: description: namespaces specifies a static list of namespace names that the term applies to. The term is applied @@ -633,6 +640,7 @@ spec: The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: description: A label query over the set of namespaces that the term applies to. The term is applied @@ -689,6 +697,7 @@ spec: The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: description: namespaces specifies a static list of namespace names that the term applies to. The @@ -787,6 +796,7 @@ spec: requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaceSelector: description: A label query over the set of namespaces that the term applies to. The term is applied to the @@ -838,6 +848,7 @@ spec: requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: description: namespaces specifies a static list of namespace names that the term applies to. The term is applied @@ -916,6 +927,7 @@ spec: required: - key type: object + x-kubernetes-map-type: atomic fieldRef: description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, @@ -933,6 +945,7 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, @@ -957,6 +970,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic secretKeyRef: description: Selects a key of a secret in the pod's namespace properties: @@ -975,6 +989,7 @@ spec: required: - key type: object + x-kubernetes-map-type: atomic type: object required: - name @@ -1001,6 +1016,7 @@ spec: description: Specify whether the ConfigMap must be defined type: boolean type: object + x-kubernetes-map-type: atomic prefix: description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. @@ -1016,6 +1032,7 @@ spec: description: Specify whether the Secret must be defined type: boolean type: object + x-kubernetes-map-type: atomic type: object type: array image: @@ -1047,6 +1064,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic type: array metadata: description: Metadata that will be added to the provider Pod. @@ -1326,6 +1344,9 @@ spec: - name type: object type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map limits: additionalProperties: anyOf: @@ -1744,6 +1765,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic user: description: 'user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' @@ -1775,6 +1797,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic volumeID: description: 'volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' @@ -1846,6 +1869,7 @@ spec: keys must be defined type: boolean type: object + x-kubernetes-map-type: atomic csi: description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta @@ -1876,6 +1900,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic readOnly: description: readOnly specifies a read-only configuration for the volume. Defaults to false (read/write). @@ -1929,6 +1954,7 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic mode: description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 @@ -1972,6 +1998,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic required: - path type: object @@ -2088,10 +2115,10 @@ spec: referenced type: string required: - - apiGroup - kind - name type: object + x-kubernetes-map-type: atomic dataSourceRef: description: 'dataSourceRef specifies the object from which to populate the volume with data, if @@ -2153,7 +2180,6 @@ spec: to be enabled. type: string required: - - apiGroup - kind - name type: object @@ -2187,6 +2213,9 @@ spec: - name type: object type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map limits: additionalProperties: anyOf: @@ -2263,6 +2292,7 @@ spec: The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic storageClassName: description: 'storageClassName is the name of the StorageClass required by the claim. More info: @@ -2353,6 +2383,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic required: - driver type: object @@ -2530,6 +2561,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic targetPortal: description: targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than @@ -2700,6 +2732,7 @@ spec: or its keys must be defined type: boolean type: object + x-kubernetes-map-type: atomic downwardAPI: description: downwardAPI information about the downwardAPI data to project @@ -2729,6 +2762,7 @@ spec: required: - fieldPath type: object + x-kubernetes-map-type: atomic mode: description: 'Optional: mode bits used to set permissions on this file, must be @@ -2777,6 +2811,7 @@ spec: required: - resource type: object + x-kubernetes-map-type: atomic required: - path type: object @@ -2842,6 +2877,7 @@ spec: Secret or its key must be defined type: boolean type: object + x-kubernetes-map-type: atomic serviceAccountToken: description: serviceAccountToken is information about the serviceAccountToken data to project @@ -2876,8 +2912,6 @@ spec: type: object type: object type: array - required: - - sources type: object quobyte: description: quobyte represents a Quobyte mount on the host @@ -2960,6 +2994,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic user: description: 'user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' @@ -2999,6 +3034,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic sslEnabled: description: sslEnabled Flag enable/disable SSL communication with Gateway, default false @@ -3114,6 +3150,7 @@ spec: TODO: Add other useful fields. apiVersion, kind, uid?' type: string type: object + x-kubernetes-map-type: atomic volumeName: description: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within diff --git a/cluster/crds/pkg.crossplane.io_locks.yaml b/cluster/crds/pkg.crossplane.io_locks.yaml index 3e651c690..35b9bdce5 100644 --- a/cluster/crds/pkg.crossplane.io_locks.yaml +++ b/cluster/crds/pkg.crossplane.io_locks.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: locks.pkg.crossplane.io spec: group: pkg.crossplane.io diff --git a/cluster/crds/pkg.crossplane.io_providerrevisions.yaml b/cluster/crds/pkg.crossplane.io_providerrevisions.yaml index 2bce681e7..09ed346da 100644 --- a/cluster/crds/pkg.crossplane.io_providerrevisions.yaml +++ b/cluster/crds/pkg.crossplane.io_providerrevisions.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: providerrevisions.pkg.crossplane.io spec: group: pkg.crossplane.io diff --git a/cluster/crds/pkg.crossplane.io_providers.yaml b/cluster/crds/pkg.crossplane.io_providers.yaml index 24aec830c..3c688ed08 100644 --- a/cluster/crds/pkg.crossplane.io_providers.yaml +++ b/cluster/crds/pkg.crossplane.io_providers.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: providers.pkg.crossplane.io spec: group: pkg.crossplane.io diff --git a/cluster/crds/secrets.crossplane.io_storeconfigs.yaml b/cluster/crds/secrets.crossplane.io_storeconfigs.yaml index b25f5a857..8ac52a44a 100644 --- a/cluster/crds/secrets.crossplane.io_storeconfigs.yaml +++ b/cluster/crds/secrets.crossplane.io_storeconfigs.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: storeconfigs.secrets.crossplane.io spec: group: secrets.crossplane.io diff --git a/cluster/meta/meta.pkg.crossplane.io_configurations.yaml b/cluster/meta/meta.pkg.crossplane.io_configurations.yaml index 08287e50b..0c9ef7f7f 100644 --- a/cluster/meta/meta.pkg.crossplane.io_configurations.yaml +++ b/cluster/meta/meta.pkg.crossplane.io_configurations.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: configurations.meta.pkg.crossplane.io spec: group: meta.pkg.crossplane.io diff --git a/cluster/meta/meta.pkg.crossplane.io_functions.yaml b/cluster/meta/meta.pkg.crossplane.io_functions.yaml index f03a8146d..2d197bd5d 100644 --- a/cluster/meta/meta.pkg.crossplane.io_functions.yaml +++ b/cluster/meta/meta.pkg.crossplane.io_functions.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: functions.meta.pkg.crossplane.io spec: group: meta.pkg.crossplane.io diff --git a/cluster/meta/meta.pkg.crossplane.io_providers.yaml b/cluster/meta/meta.pkg.crossplane.io_providers.yaml index 1040e7af7..c944df06f 100644 --- a/cluster/meta/meta.pkg.crossplane.io_providers.yaml +++ b/cluster/meta/meta.pkg.crossplane.io_providers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.12.1 name: providers.meta.pkg.crossplane.io spec: group: meta.pkg.crossplane.io From f98fc2baba5872974bfc8f6ffd753973d6fdae8c Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 19 Jul 2023 09:02:14 +0200 Subject: [PATCH 093/148] fix(alpha): re-evaluating additional fields against schema Signed-off-by: Philippe Scorsolini --- .../apiextensions/v1/composition/patches.go | 3 ++- .../apiextensions/v1/composition/patches_test.go | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/validation/apiextensions/v1/composition/patches.go b/pkg/validation/apiextensions/v1/composition/patches.go index 4438a5087..df81c238d 100644 --- a/pkg/validation/apiextensions/v1/composition/patches.go +++ b/pkg/validation/apiextensions/v1/composition/patches.go @@ -420,7 +420,8 @@ func validateFieldPathSegmentField(parent *apiextensions.JSONSchemaProps, segmen // Schema is not nil. // See https://github.com/kubernetes/kubernetes/blob/ff4eff24ac4fad5431aa89681717d6c4fe5733a4/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go#L828 if parent.AdditionalProperties != nil && (parent.AdditionalProperties.Allows || parent.AdditionalProperties.Schema != nil) { - return parent.AdditionalProperties.Schema, nil + // re-evaluate the segment against the additional properties schema + return validateFieldPathSegmentField(parent.AdditionalProperties.Schema, segment) } return nil, errors.Errorf(errFmtFieldInvalid, segment.Field) diff --git a/pkg/validation/apiextensions/v1/composition/patches_test.go b/pkg/validation/apiextensions/v1/composition/patches_test.go index e57ab9cd8..b00b4e747 100644 --- a/pkg/validation/apiextensions/v1/composition/patches_test.go +++ b/pkg/validation/apiextensions/v1/composition/patches_test.go @@ -444,6 +444,22 @@ func TestValidateFieldPath(t *testing.T) { schema: &apiextensions.JSONSchemaProps{Properties: map[string]apiextensions.JSONSchemaProps{"metadata": {Type: "object"}}}, }, }, + "AcceptXPreserveUnknownFieldsInAdditionalProperties": { + reason: "Should properly handle x-preserve-unknown-fields even if defined in a nested schema", + want: want{err: nil, fieldType: ""}, + args: args{ + fieldPath: "data.someField", + schema: &apiextensions.JSONSchemaProps{ + Properties: map[string]apiextensions.JSONSchemaProps{ + "data": { + Type: "object", + AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{ + Schema: &apiextensions.JSONSchemaProps{ + XPreserveUnknownFields: &[]bool{true}[0], + }, + }, + }}}}, + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { From 962a91b190d773004a36565c0032bf61bce5e990 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:11:44 +0000 Subject: [PATCH 094/148] Update module github.com/bufbuild/buf to v1.25.0 --- go.mod | 8 ++++---- go.sum | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 6afa5e03d..7273ee7c2 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 - github.com/bufbuild/buf v1.24.0 + github.com/bufbuild/buf v1.25.0 github.com/crossplane/crossplane-runtime v0.20.0 github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 @@ -82,7 +82,7 @@ require ( github.com/docker/cli v24.0.4+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.4+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect @@ -91,7 +91,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-chi/chi/v5 v5.0.8 // indirect + github.com/go-chi/chi/v5 v5.0.10 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -153,7 +153,7 @@ require ( github.com/ryanuber/go-glob v1.0.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/tetratelabs/wazero v1.2.1 // indirect + github.com/tetratelabs/wazero v1.3.0 // indirect github.com/vbatts/tar-split v0.11.3 // indirect github.com/vladimirvivien/gexe v0.2.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect diff --git a/go.sum b/go.sum index 97cb8ee63..f0248cbe1 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,8 @@ github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bufbuild/buf v1.24.0 h1:36rVJMJX7BI9Z6nUPpirF+TUO9tVZ45u5VAfj5E7Bgw= -github.com/bufbuild/buf v1.24.0/go.mod h1:cacBvncWbYnUcNX580lqllR3qlEetMX/KVm27pUc4Kc= +github.com/bufbuild/buf v1.25.0 h1:HFxKrR8wFcZwrBInN50K/oJX/WOtPVq24rHb/ArjfBA= +github.com/bufbuild/buf v1.25.0/go.mod h1:GCKZ5bAP6Ht4MF7KcfaGVgBEXGumwAz2hXjjLVxx8ZU= github.com/bufbuild/connect-go v1.9.0 h1:JIgAeNuFpo+SUPfU19Yt5TcWlznsN5Bv10/gI/6Pjoc= github.com/bufbuild/connect-go v1.9.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= github.com/bufbuild/connect-opentelemetry-go v0.4.0 h1:6JAn10SNqlQ/URhvRNGrIlczKw1wEXknBUUtmWqOiak= @@ -180,8 +180,9 @@ github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m3 github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= 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= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -209,8 +210,8 @@ github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= -github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -500,8 +501,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/tetratelabs/wazero v1.2.1 h1:J4X2hrGzJvt+wqltuvcSjHQ7ujQxA9gb6PeMs4qlUWs= -github.com/tetratelabs/wazero v1.2.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= +github.com/tetratelabs/wazero v1.3.0 h1:nqw7zCldxE06B8zSZAY0ACrR9OH5QCcPwYmYlwtcwtE= +github.com/tetratelabs/wazero v1.3.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= From 65fc720d862bf562f52f8cb4926d7188325d177f Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 13 Jul 2023 14:43:28 +0200 Subject: [PATCH 095/148] fix: stop rbac manager's rule expansion on timeout Signed-off-by: Philippe Scorsolini --- .../rbac/provider/roles/requests.go | 37 ++- .../rbac/provider/roles/requests_test.go | 226 ++++++++++++++---- 2 files changed, 205 insertions(+), 58 deletions(-) diff --git a/internal/controller/rbac/provider/roles/requests.go b/internal/controller/rbac/provider/roles/requests.go index a463ababa..939a901d9 100644 --- a/internal/controller/rbac/provider/roles/requests.go +++ b/internal/controller/rbac/provider/roles/requests.go @@ -29,7 +29,9 @@ import ( // Error strings. const ( - errGetClusterRole = "cannot get ClusterRole" + errGetClusterRole = "cannot get ClusterRole" + errExpandClusterRoleRules = "cannot expand ClusterRole rules" + errExpandPermissionRequests = "cannot expand PermissionRequests" ) const ( @@ -126,11 +128,17 @@ func (r Rule) path() path { } // Expand RBAC policy rules into our granular rules. -func Expand(rs ...rbacv1.PolicyRule) []Rule { +func Expand(ctx context.Context, rs ...rbacv1.PolicyRule) ([]Rule, error) { //nolint:gocyclo // Granular rules are inherently complex. out := make([]Rule, 0, len(rs)) for _, r := range rs { for _, u := range r.NonResourceURLs { for _, v := range r.Verbs { + // exit if ctx is done + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } out = append(out, Rule{NonResourceURL: u, Verb: v}) } } @@ -147,13 +155,18 @@ func Expand(rs ...rbacv1.PolicyRule) []Rule { for _, rsc := range r.Resources { for _, n := range names { for _, v := range r.Verbs { + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } out = append(out, Rule{APIGroup: g, Resource: rsc, ResourceName: n, Verb: v}) } } } } } - return out + return out, nil } // A ClusterRoleBackedValidator is a PermissionRequestsValidator that validates @@ -170,7 +183,7 @@ func NewClusterRoleBackedValidator(c client.Client, roleName string) *ClusterRol return &ClusterRoleBackedValidator{client: c, name: roleName} } -// ValidatePermissionRequests against the ClusterRole. +// ValidatePermissionRequests against the ClusterRole, returning the list of rejected rules. func (v *ClusterRoleBackedValidator) ValidatePermissionRequests(ctx context.Context, requests ...rbacv1.PolicyRule) ([]Rule, error) { cr := &rbacv1.ClusterRole{} if err := v.client.Get(ctx, types.NamespacedName{Name: v.name}, cr); err != nil { @@ -178,12 +191,20 @@ func (v *ClusterRoleBackedValidator) ValidatePermissionRequests(ctx context.Cont } t := newNode() - for _, rule := range Expand(cr.Rules...) { + expandedCrRules, err := Expand(ctx, cr.Rules...) + if err != nil { + return nil, errors.Wrap(err, errExpandClusterRoleRules) + } + for _, rule := range expandedCrRules { t.Allow(rule.path()) } rejected := make([]Rule, 0) - for _, rule := range Expand(requests...) { + expandedRequests, err := Expand(ctx, requests...) + if err != nil { + return nil, errors.Wrap(err, errExpandPermissionRequests) + } + for _, rule := range expandedRequests { if !t.Allowed(rule.path()) { rejected = append(rejected, rule) } @@ -194,6 +215,6 @@ func (v *ClusterRoleBackedValidator) ValidatePermissionRequests(ctx context.Cont // VerySecureValidator is a PermissionRequestsValidatorFn that rejects all // requested permissions. -func VerySecureValidator(_ context.Context, requests ...rbacv1.PolicyRule) ([]Rule, error) { - return Expand(requests...), nil +func VerySecureValidator(ctx context.Context, requests ...rbacv1.PolicyRule) ([]Rule, error) { + return Expand(ctx, requests...) } diff --git a/internal/controller/rbac/provider/roles/requests_test.go b/internal/controller/rbac/provider/roles/requests_test.go index be1535577..d4de22b16 100644 --- a/internal/controller/rbac/provider/roles/requests_test.go +++ b/internal/controller/rbac/provider/roles/requests_test.go @@ -83,79 +83,129 @@ func TestAllowed(t *testing.T) { } func TestExpand(t *testing.T) { + type args struct { + rs []rbacv1.PolicyRule + ctx context.Context + } + type want struct { + err error + rules []Rule + } cases := map[string]struct { reason string - rs []rbacv1.PolicyRule - want []Rule + args + want }{ "SimpleURL": { reason: "It should be possible to expand a simple, granular non-resource RBAC rule.", - rs: []rbacv1.PolicyRule{{ - NonResourceURLs: []string{"/api"}, - Verbs: []string{"get"}, - }}, - want: []Rule{{ - NonResourceURL: "/api", - Verb: "get", - }}, + args: args{ + rs: []rbacv1.PolicyRule{{ + NonResourceURLs: []string{"/api"}, + Verbs: []string{"get"}, + }}, + }, + want: want{ + rules: []Rule{{ + NonResourceURL: "/api", + Verb: "get", + }}, + }, }, "SimpleResource": { reason: "It should be possible to expand a simple, granular resource RBAC rule.", - rs: []rbacv1.PolicyRule{{ - APIGroups: []string{""}, - Resources: []string{"*"}, - Verbs: []string{"get"}, - }}, - want: []Rule{{ - APIGroup: "", - Resource: "*", - ResourceName: "*", - Verb: "get", - }}, + args: args{ + rs: []rbacv1.PolicyRule{{ + APIGroups: []string{""}, + Resources: []string{"*"}, + Verbs: []string{"get"}, + }}, + }, + want: want{ + rules: []Rule{{ + APIGroup: "", + Resource: "*", + ResourceName: "*", + Verb: "get", + }}, + }, }, "ComplexResource": { reason: "It should be possible to expand a more complex resource RBAC rule.", - rs: []rbacv1.PolicyRule{ - {APIGroups: []string{""}, Resources: []string{"*"}, Verbs: []string{"get", "list", "watch"}}, - {APIGroups: []string{"example"}, Resources: []string{"examples", "others"}, ResourceNames: []string{"barry", "hank"}, Verbs: []string{"get"}}, + args: args{ + rs: []rbacv1.PolicyRule{ + {APIGroups: []string{""}, Resources: []string{"*"}, Verbs: []string{"get", "list", "watch"}}, + {APIGroups: []string{"example"}, Resources: []string{"examples", "others"}, ResourceNames: []string{"barry", "hank"}, Verbs: []string{"get"}}, + }, }, - want: []Rule{ - {APIGroup: "", Resource: "*", ResourceName: "*", Verb: "get"}, - {APIGroup: "", Resource: "*", ResourceName: "*", Verb: "list"}, - {APIGroup: "", Resource: "*", ResourceName: "*", Verb: "watch"}, - {APIGroup: "example", Resource: "examples", ResourceName: "barry", Verb: "get"}, - {APIGroup: "example", Resource: "examples", ResourceName: "hank", Verb: "get"}, - {APIGroup: "example", Resource: "others", ResourceName: "barry", Verb: "get"}, - {APIGroup: "example", Resource: "others", ResourceName: "hank", Verb: "get"}, + want: want{ + rules: []Rule{ + {APIGroup: "", Resource: "*", ResourceName: "*", Verb: "get"}, + {APIGroup: "", Resource: "*", ResourceName: "*", Verb: "list"}, + {APIGroup: "", Resource: "*", ResourceName: "*", Verb: "watch"}, + {APIGroup: "example", Resource: "examples", ResourceName: "barry", Verb: "get"}, + {APIGroup: "example", Resource: "examples", ResourceName: "hank", Verb: "get"}, + {APIGroup: "example", Resource: "others", ResourceName: "barry", Verb: "get"}, + {APIGroup: "example", Resource: "others", ResourceName: "hank", Verb: "get"}, + }, }, }, "Combo": { reason: "We should faithfully expand a rule with both URLs and resources. This is invalid, but we let Kubernetes police that.", - rs: []rbacv1.PolicyRule{{ - APIGroups: []string{""}, - Resources: []string{"*"}, - NonResourceURLs: []string{"/api"}, - Verbs: []string{"get"}, - }}, - want: []Rule{ - { - NonResourceURL: "/api", - Verb: "get", - }, - { - APIGroup: "", - Resource: "*", - ResourceName: "*", - Verb: "get", + args: args{ + rs: []rbacv1.PolicyRule{{ + APIGroups: []string{""}, + Resources: []string{"*"}, + NonResourceURLs: []string{"/api"}, + Verbs: []string{"get"}, + }}, + }, + want: want{ + rules: []Rule{ + { + NonResourceURL: "/api", + Verb: "get", + }, + { + APIGroup: "", + Resource: "*", + ResourceName: "*", + Verb: "get", + }, }, }, }, + "ComboCtxCancelled": { + reason: "We should return an error if the context is cancelled.", + args: args{ + rs: []rbacv1.PolicyRule{{ + APIGroups: []string{""}, + Resources: []string{"*"}, + NonResourceURLs: []string{"/api"}, + Verbs: []string{"get"}, + }}, + ctx: func() context.Context { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + return ctx + }(), + }, + want: want{ + err: context.Canceled, + }, + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { - got := Expand(tc.rs...) - if diff := cmp.Diff(tc.want, got); diff != "" { + ctx := tc.args.ctx + if ctx == nil { + ctx = context.Background() + } + got, err := Expand(ctx, tc.rs...) + if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { + t.Errorf("\n%s\nExpand(...): -want error, +got error:\n%s", tc.reason, diff) + } + if diff := cmp.Diff(tc.want.rules, got); diff != "" { t.Errorf("\n%s\nExpand(...): -want, +got:\n%s", tc.reason, diff) } }) @@ -229,6 +279,7 @@ func TestValidatePermissionRequests(t *testing.T) { }, }, args: args{ + ctx: context.Background(), requests: []rbacv1.PolicyRule{ // Allowed - we allow * on secrets. { @@ -270,6 +321,81 @@ func TestValidatePermissionRequests(t *testing.T) { }, }, }, + "SuccessfulRejectEvenWithTimeout": { + fields: fields{ + c: &test.MockClient{ + MockGet: test.NewMockGetFn(nil, func(obj client.Object) error { + cr := obj.(*rbacv1.ClusterRole) + cr.Rules = []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"secrets", "configmaps", "events"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"apps", "extensions"}, + Resources: []string{"deployments"}, + Verbs: []string{"get"}, + }, + { + APIGroups: []string{"apps"}, + Resources: []string{"deployments"}, + Verbs: []string{"list"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"pods"}, + ResourceNames: []string{"this-one-really-cool-pod"}, + Verbs: []string{"*"}, + }, + } + return nil + }), + }, + }, + args: args{ + ctx: func() context.Context { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + return ctx + }(), + requests: []rbacv1.PolicyRule{ + // Allowed - we allow * on secrets. + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"*"}, + }, + // Allowed - we allow * on configmaps. + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"get", "list", "watch"}, + }, + // Rejected - we don't allow get on extensions/deployments. + { + APIGroups: []string{"extensions"}, + Resources: []string{"deployments"}, + Verbs: []string{"get", "list"}, + }, + // Allowed - we allow get and list on apps/deployments. + { + APIGroups: []string{"apps"}, + Resources: []string{"deployments"}, + Verbs: []string{"get", "list"}, + }, + // Rejected - we only allow access to really cool pods. + { + APIGroups: []string{""}, + Resources: []string{"pods"}, + Verbs: []string{"get", "list"}, + }, + }, + }, + want: want{ + err: errors.Wrap(context.Canceled, errExpandClusterRoleRules), + }, + }, } for name, tc := range cases { From 7d76b2312e068500220a8d534f0e53e9dc9230d1 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 19 Jul 2023 10:07:30 +0200 Subject: [PATCH 096/148] chore: bump go-containerregistry to v0.15.3-0.20230625233257-b8504803389b Signed-off-by: Philippe Scorsolini --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6afa5e03d..83e4032ea 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/crossplane/crossplane-runtime v0.20.0 github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 - github.com/google/go-containerregistry v0.15.2 + github.com/google/go-containerregistry v0.15.3-0.20230625233257-b8504803389b github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230617045147-2472cbbbf289 github.com/google/uuid v1.3.0 github.com/jmattheis/goverter v0.17.4 diff --git a/go.sum b/go.sum index 97cb8ee63..e420beab8 100644 --- a/go.sum +++ b/go.sum @@ -292,8 +292,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= -github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= +github.com/google/go-containerregistry v0.15.3-0.20230625233257-b8504803389b h1:nEV+eNboccNOCOkad/Zkx7nYG/xsk8cceS2Zew/VPzk= +github.com/google/go-containerregistry v0.15.3-0.20230625233257-b8504803389b/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230617045147-2472cbbbf289 h1:wk0QZFyD9RapJgFdQGb8+5+RtNxJsrVYpdEHfTc3Q8g= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230617045147-2472cbbbf289/go.mod h1:Ek+8PQrShkA7aHEj3/zSW33wU0V/Bx3zW/gFh7l21xY= github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230516205744-dbecb1de8cfa h1:+MG+Q2Q7mtW6kCIbUPZ9ZMrj7xOWDKI1hhy1qp0ygI0= From 253d5ba3ed50c7495f1dc4a6a11e6340bb1df9c7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 16:06:08 +0000 Subject: [PATCH 097/148] Update github/codeql-action digest to 1813ca7 --- .github/workflows/ci.yml | 4 ++-- .github/workflows/scan.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1ef44779..7322164ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,12 @@ jobs: run: make vendor vendor.check - name: Initialize CodeQL - uses: github/codeql-action/init@489225d82a57396c6f426a40e66d461b16b3461d # v2 + uses: github/codeql-action/init@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@489225d82a57396c6f426a40e66d461b16b3461d # v2 + uses: github/codeql-action/analyze@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2 trivy-scan-fs: runs-on: ubuntu-22.04 diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml index 788497e57..bfcaf4b30 100644 --- a/.github/workflows/scan.yaml +++ b/.github/workflows/scan.yaml @@ -131,7 +131,7 @@ jobs: retention-days: 3 - name: Upload Trivy Scan Results To GitHub Security Tab - uses: github/codeql-action/upload-sarif@489225d82a57396c6f426a40e66d461b16b3461d # v2 + uses: github/codeql-action/upload-sarif@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2 with: sarif_file: 'trivy-results.sarif' category: ${{ matrix.image }}:${{ env.tag }} From abcc64ec48a7c63ff6c14be35cd404b05be72be8 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 13 Jul 2023 14:36:11 +0200 Subject: [PATCH 098/148] fix: limit max number of layers for Packages Signed-off-by: Philippe Scorsolini --- internal/controller/pkg/revision/imageback.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/controller/pkg/revision/imageback.go b/internal/controller/pkg/revision/imageback.go index 989e5c100..bbad98662 100644 --- a/internal/controller/pkg/revision/imageback.go +++ b/internal/controller/pkg/revision/imageback.go @@ -39,11 +39,14 @@ const ( errGetUncompressed = "failed to get uncompressed contents from layer" errMultipleAnnotatedLayers = "package is invalid due to multiple annotated base layers" errOpenPackageStream = "failed to open package stream file" + errFmtMaxManifestLayers = "package has %d layers, but only %d are allowed" ) const ( layerAnnotation = "io.crossplane.xpkg" baseAnnotationValue = "base" + // maxLayers is the maximum number of layers an image can have. + maxLayers = 256 ) // ImageBackend is a backend for parser. @@ -101,6 +104,12 @@ func (i *ImageBackend) Init(ctx context.Context, bo ...parser.BackendOption) (io if err != nil { return nil, errors.Wrap(err, errGetManifest) } + + // Check that the image has less than the maximum allowed number of layers. + if nLayers := len(manifest.Layers); nLayers > maxLayers { + return nil, errors.Errorf(errFmtMaxManifestLayers, nLayers, maxLayers) + } + // Determine if the image is using annotated layers. var tarc io.ReadCloser foundAnnotated := false From 2c2d6c3d5304a968396e59932e07480ce748df32 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Thu, 20 Jul 2023 10:39:01 +0100 Subject: [PATCH 099/148] Update internal/dag/dag.go Co-authored-by: Philippe Scorsolini Signed-off-by: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> --- internal/dag/dag.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/dag/dag.go b/internal/dag/dag.go index 39f14a20b..37d3e2ac5 100644 --- a/internal/dag/dag.go +++ b/internal/dag/dag.go @@ -214,7 +214,7 @@ func (d *MapDag) visit(name string, neighbors []Node, stack map[string]bool, vis for _, n := range neighbors { if !visited[n.Identifier()] { if _, ok := d.nodes[n.Identifier()]; !ok { - return errors.Errorf("node does not exist") + return errors.Errorf("node %q does not exist", n.Identifier()) } if err := d.visit(n.Identifier(), d.nodes[n.Identifier()].Neighbors(), stack, visited, results); err != nil { return err From 71fcb583cf0e6d61598b7bf06a9655c23ab22951 Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Thu, 13 Jul 2023 12:12:43 +0300 Subject: [PATCH 100/148] Add e2e test for XFN /tmp write access Signed-off-by: ezgidemirel --- Makefile | 2 + .../manifests/xfnrunner/tmp-writer/claim.yaml | 9 ++ .../xfnrunner/tmp-writer/composition.yaml | 39 +++++ .../tmp-writer/prerequisites/definition.yaml | 29 ++++ .../tmp-writer/prerequisites/provider.yaml | 7 + .../e2e/testdata/images/tmp-writer/Dockerfile | 7 + test/e2e/testdata/images/tmp-writer/writer.sh | 4 + test/e2e/xfn_test.go | 149 ++++++++++++++++++ 8 files changed, 246 insertions(+) create mode 100644 test/e2e/manifests/xfnrunner/tmp-writer/claim.yaml create mode 100644 test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml create mode 100644 test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/definition.yaml create mode 100644 test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/provider.yaml create mode 100644 test/e2e/testdata/images/tmp-writer/Dockerfile create mode 100755 test/e2e/testdata/images/tmp-writer/writer.sh diff --git a/Makefile b/Makefile index 6c135121a..c8d82acb1 100644 --- a/Makefile +++ b/Makefile @@ -121,6 +121,7 @@ cobertura: e2e.test.images: @$(INFO) Building E2E test images @docker build --load -t $(BUILD_REGISTRY)/fn-labelizer-$(TARGETARCH) test/e2e/testdata/images/labelizer + @docker build --load -t $(BUILD_REGISTRY)/fn-tmp-writer-$(TARGETARCH) test/e2e/testdata/images/tmp-writer @$(OK) Built E2E test images e2e-tag-images: e2e.test.images @@ -128,6 +129,7 @@ e2e-tag-images: e2e.test.images @docker tag $(BUILD_REGISTRY)/$(PROJECT_NAME)-$(TARGETARCH) crossplane-e2e/$(PROJECT_NAME):latest || $(FAIL) @docker tag $(BUILD_REGISTRY)/xfn-$(TARGETARCH) crossplane-e2e/xfn:latest || $(FAIL) @docker tag $(BUILD_REGISTRY)/fn-labelizer-$(TARGETARCH) crossplane-e2e/fn-labelizer:latest || $(FAIL) + @docker tag $(BUILD_REGISTRY)/fn-tmp-writer-$(TARGETARCH) crossplane-e2e/fn-tmp-writer:latest || $(FAIL) @$(OK) Tagged E2E test images # NOTE(negz): There's already a go.test.integration target, but it's weird. diff --git a/test/e2e/manifests/xfnrunner/tmp-writer/claim.yaml b/test/e2e/manifests/xfnrunner/tmp-writer/claim.yaml new file mode 100644 index 000000000..d2e90fd0b --- /dev/null +++ b/test/e2e/manifests/xfnrunner/tmp-writer/claim.yaml @@ -0,0 +1,9 @@ +apiVersion: nop.example.org/v1alpha1 +kind: NopResource +metadata: + name: fn-tmp-writer + namespace: default +spec: + coolField: example + compositionRef: + name: fn.xnopresources.nop.example.org \ No newline at end of file diff --git a/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml b/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml new file mode 100644 index 000000000..7f9675b5e --- /dev/null +++ b/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml @@ -0,0 +1,39 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: fn.xnopresources.nop.example.org + labels: + provider: provider-nop +spec: + compositeTypeRef: + apiVersion: nop.example.org/v1alpha1 + kind: XNopResource + resources: + - name: nopinstance1 + base: + apiVersion: nop.crossplane.io/v1alpha1 + kind: NopResource + spec: + forProvider: + conditionAfter: + - conditionType: Ready + conditionStatus: "False" + time: 0s + - conditionType: Ready + conditionStatus: "True" + time: 10s + - conditionType: Synced + conditionStatus: "False" + time: 0s + - conditionType: Synced + conditionStatus: "True" + time: 10s + writeConnectionSecretsToRef: + namespace: crossplane-system + name: nop-example-resource + functions: + - name: tmp-writer + type: Container + container: + image: public-docker-registry.reg.svc.cluster.local:5000/fn-tmp-writer:latest + imagePullPolicy: Always \ No newline at end of file diff --git a/test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/definition.yaml b/test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/definition.yaml new file mode 100644 index 000000000..bf70cb798 --- /dev/null +++ b/test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/definition.yaml @@ -0,0 +1,29 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: CompositeResourceDefinition +metadata: + name: xnopresources.nop.example.org +spec: + group: nop.example.org + names: + kind: XNopResource + plural: xnopresources + claimNames: + kind: NopResource + plural: nopresources + connectionSecretKeys: + - test + versions: + - name: v1alpha1 + served: true + referenceable: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + coolField: + type: string + required: + - coolField \ No newline at end of file diff --git a/test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/provider.yaml b/test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/provider.yaml new file mode 100644 index 000000000..2f8d0708f --- /dev/null +++ b/test/e2e/manifests/xfnrunner/tmp-writer/prerequisites/provider.yaml @@ -0,0 +1,7 @@ +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-nop +spec: + package: xpkg.upbound.io/crossplane-contrib/provider-nop:v0.2.0 + ignoreCrossplaneConstraints: true \ No newline at end of file diff --git a/test/e2e/testdata/images/tmp-writer/Dockerfile b/test/e2e/testdata/images/tmp-writer/Dockerfile new file mode 100644 index 000000000..3e338c8aa --- /dev/null +++ b/test/e2e/testdata/images/tmp-writer/Dockerfile @@ -0,0 +1,7 @@ +FROM mikefarah/yq:4.34.1 + +COPY writer.sh /bin +USER root +RUN chmod +x /bin/writer.sh + +ENTRYPOINT ["/bin/writer.sh"] \ No newline at end of file diff --git a/test/e2e/testdata/images/tmp-writer/writer.sh b/test/e2e/testdata/images/tmp-writer/writer.sh new file mode 100755 index 000000000..dfe9229fe --- /dev/null +++ b/test/e2e/testdata/images/tmp-writer/writer.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +touch "/tmp/foo.txt" +yq '(.desired.resources[] | .resource.metadata.annotations) |= {"lines": "finally!"} + .' diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 5f5984c53..0dc09fc12 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -227,3 +227,152 @@ func TestXfnRunnerImagePull(t *testing.T) { Feature(), ) } + +func TestXfnRunnerWriteToTmp(t *testing.T) { + manifests := "test/e2e/manifests/xfnrunner/tmp-writer" + environment.Test(t, + features.New("CreateAFileInTmpFolder"). + WithLabel(LabelArea, "xfn"). + WithSetup("InstallRegistry", + funcs.AllOf( + funcs.AsFeaturesFunc(envfuncs.CreateNamespace("reg")), + funcs.AsFeaturesFunc( + funcs.HelmRepo( + helm.WithArgs("add"), + helm.WithArgs("twuni"), + helm.WithArgs("https://helm.twun.io"), + )), + funcs.AsFeaturesFunc( + funcs.HelmInstall( + helm.WithName("public"), + helm.WithNamespace("reg"), + helm.WithWait(), + helm.WithChart("twuni/docker-registry"), + helm.WithVersion("2.2.2"), + helm.WithArgs( + "--set service.type=NodePort", + "--set service.nodePort=32000", + ), + ))), + ). + WithSetup("CopyFnImageToRegistry", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + nodes := &corev1.NodeList{} + if err := config.Client().Resources().List(ctx, nodes); err != nil { + t.Fatal("cannot list nodes", err) + } + if len(nodes.Items) == 0 { + t.Fatalf("no nodes in the cluster") + } + + var addr string + for _, a := range nodes.Items[0].Status.Addresses { + if a.Type == corev1.NodeInternalIP { + addr = a.Address + break + } + } + if addr == "" { + t.Fatalf("no nodes with private address") + } + + srcRef, err := name.ParseReference("crossplane-e2e/fn-tmp-writer:latest") + if err != nil { + t.Fatal(err) + } + + src, err := daemon.Image(srcRef) + if err != nil { + t.Fatal(err) + } + + err = wait.For(func() (done bool, err error) { + err = crane.Push(src, fmt.Sprintf("%s:32000/fn-tmp-writer:latest", addr), crane.Insecure) + if err != nil { + return false, nil //nolint:nilerr // we want to retry and to throw error + } + return true, nil + }, wait.WithTimeout(1*time.Minute)) + if err != nil { + t.Fatal("copying image to registry not successful", err) + } + return ctx + }). + WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade( + HelmOptions( + helm.WithArgs( + "--set args={--debug,--enable-composition-functions}", + "--set xfn.enabled=true", + "--set xfn.args={--debug}", + "--set xfn.resources.requests.cpu=100m", + "--set xfn.resources.limits.cpu=100m", + ), + helm.WithWait())...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). + WithSetup("ProviderNopDeployed", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "prerequisites/provider.yaml"), + funcs.ApplyResources(FieldManager, manifests, "prerequisites/definition.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), + funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, "prerequisites/definition.yaml", v1.WatchingComposite()), + )). + Assess("CompositionWithFunctionIsCreated", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "composition.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "composition.yaml"), + )). + Assess("ClaimIsCreated", funcs.AllOf( + funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), + funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), + )). + Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ManagedResourcesProcessedByFunction", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { + annotationName := "lines" + rg := utils.NewResourceGetter(ctx, t, config) + claim := rg.Get("fn-tmp-writer", "default", "nop.example.org/v1alpha1", "NopResource") + r := utils.ResourceValue(t, claim, "spec", "resourceRef") + + xr := rg.Get(r["name"], "default", r["apiVersion"], r["kind"]) + mrefs := utils.ResourceSliceValue(t, xr, "spec", "resourceRefs") + for _, mref := range mrefs { + err := wait.For(func() (done bool, err error) { + mr := rg.Get(mref["name"], "default", mref["apiVersion"], mref["kind"]) + a, found := mr.GetAnnotations()[annotationName] + if !found { + return false, nil + } + if a != "finally!" { + return false, nil + } + return true, nil + }, wait.WithTimeout(5*time.Minute)) + if err != nil { + t.Fatalf("Expected annottion %v value is `finally!`", annotationName) + } + } + return ctx + }). + WithTeardown("DeleteClaim", funcs.AllOf( + funcs.DeleteResources(manifests, "claim.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), + )). + WithTeardown("DeleteComposition", funcs.AllOf( + funcs.DeleteResources(manifests, "composition.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "composition.yaml"), + )). + WithTeardown("ProviderNopRemoved", funcs.AllOf( + funcs.DeleteResources(manifests, "prerequisites/provider.yaml"), + funcs.DeleteResources(manifests, "prerequisites/definition.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), + funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), + )). + WithTeardown("RemoveRegistry", funcs.AllOf( + funcs.AsFeaturesFunc(envfuncs.DeleteNamespace("reg")), + )). + WithTeardown("CrossplaneDeployedWithoutFunctionsEnabled", funcs.AllOf( + funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), + funcs.ReadyToTestWithin(1*time.Minute, namespace), + )). + Feature(), + ) +} From 9555ef38847b36685e71a175d22dffbe2330fe14 Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Tue, 18 Jul 2023 16:31:32 +0300 Subject: [PATCH 101/148] fix image script, add CopyImageToRegistry helper Signed-off-by: ezgidemirel --- test/e2e/funcs/feature.go | 38 ++++++ .../e2e/testdata/images/tmp-writer/Dockerfile | 3 +- test/e2e/testdata/images/tmp-writer/writer.sh | 5 +- test/e2e/xfn_test.go | 111 ++++-------------- 4 files changed, 66 insertions(+), 91 deletions(-) diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index 1a942f05d..a1b01eece 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -28,6 +28,9 @@ import ( "time" "github.com/google/go-cmp/cmp" + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/daemon" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -385,6 +388,41 @@ func DeleteResources(dir, pattern string) features.Func { } } +// CopyImageToRegistry tries to copy the supplied image to the supplied registry within the timeout +func CopyImageToRegistry(clusterName, ns, sName, image string, timeout time.Duration) features.Func { + return func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { + reg, err := ServiceIngressEndPoint(ctx, c, clusterName, ns, sName) + if err != nil { + t.Fatal(err) + } + + t.Logf("registry endpoint %s", reg) + srcRef, err := name.ParseReference(image) + if err != nil { + t.Fatal(err) + } + + src, err := daemon.Image(srcRef) + if err != nil { + t.Fatal(err) + } + + i := strings.Split(srcRef.String(), "/") + err = wait.For(func() (done bool, err error) { + err = crane.Push(src, fmt.Sprintf("%s/%s", reg, i[1]), crane.Insecure) + if err != nil { + return false, nil //nolint:nilerr // we want to retry and to throw error + } + return true, nil + }, wait.WithTimeout(timeout)) + if err != nil { + t.Fatalf("copying image `%s` to registry `%s` not successful: %v", image, reg, err) + } + + return ctx + } +} + // asUnstructured turns an arbitrary runtime.Object into an *Unstructured. If // it's already a concrete *Unstructured it just returns it, otherwise it // round-trips it through JSON encoding. This is necessary because types that diff --git a/test/e2e/testdata/images/tmp-writer/Dockerfile b/test/e2e/testdata/images/tmp-writer/Dockerfile index 3e338c8aa..2c3a47fec 100644 --- a/test/e2e/testdata/images/tmp-writer/Dockerfile +++ b/test/e2e/testdata/images/tmp-writer/Dockerfile @@ -1,7 +1,6 @@ FROM mikefarah/yq:4.34.1 -COPY writer.sh /bin +COPY --chmod=+x writer.sh /bin USER root -RUN chmod +x /bin/writer.sh ENTRYPOINT ["/bin/writer.sh"] \ No newline at end of file diff --git a/test/e2e/testdata/images/tmp-writer/writer.sh b/test/e2e/testdata/images/tmp-writer/writer.sh index dfe9229fe..851ab397d 100755 --- a/test/e2e/testdata/images/tmp-writer/writer.sh +++ b/test/e2e/testdata/images/tmp-writer/writer.sh @@ -1,4 +1,5 @@ #!/usr/bin/env sh -touch "/tmp/foo.txt" -yq '(.desired.resources[] | .resource.metadata.annotations) |= {"lines": "finally!"} + .' +touch "/tmp/foo.txt" || exit 1 + +yq '(.desired.resources[] | .resource.metadata.annotations) |= {"tmp-write-access": "true"} + .' diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index 0dc09fc12..ad9b76193 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -16,13 +16,9 @@ package e2e import ( "context" - "fmt" "testing" "time" - "github.com/google/go-containerregistry/pkg/crane" - "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/daemon" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/e2e-framework/klient/wait" @@ -38,6 +34,13 @@ import ( "github.com/crossplane/crossplane/test/e2e/utils" ) +const ( + regNs = "reg" + + timeoutFive = 5 * time.Minute + timeoutOne = 1 * time.Minute +) + func TestXfnRunnerImagePull(t *testing.T) { manifests := "test/e2e/manifests/xfnrunner/private-registry/pull" @@ -46,10 +49,9 @@ func TestXfnRunnerImagePull(t *testing.T) { WithLabel(LabelArea, "xfn"). WithSetup("InstallRegistryWithCustomTlsCertificate", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.CreateNamespace("reg")), + funcs.AsFeaturesFunc(envfuncs.CreateNamespace(regNs)), func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { dnsName := "private-docker-registry.reg.svc.cluster.local" - ns := "reg" caPem, keyPem, err := utils.CreateCert(dnsName) if err != nil { t.Fatal(err) @@ -58,7 +60,7 @@ func TestXfnRunnerImagePull(t *testing.T) { secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "reg-cert", - Namespace: ns, + Namespace: regNs, }, Type: corev1.SecretTypeTLS, StringData: map[string]string{ @@ -94,7 +96,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.AsFeaturesFunc( funcs.HelmInstall( helm.WithName("private"), - helm.WithNamespace("reg"), + helm.WithNamespace(regNs), helm.WithWait(), helm.WithChart("twuni/docker-registry"), helm.WithVersion("2.2.2"), @@ -105,32 +107,8 @@ func TestXfnRunnerImagePull(t *testing.T) { ), ))), ). - WithSetup("CopyFnImageToRegistry", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - reg, err := funcs.ServiceIngressEndPoint(ctx, config, clusterName, "reg", "private-docker-registry") - if err != nil { - t.Fatal(err) - } - t.Logf("registry endpoint %s", reg) - srcRef, err := name.ParseReference("crossplane-e2e/fn-labelizer:latest") - if err != nil { - t.Fatal(err) - } - src, err := daemon.Image(srcRef) - if err != nil { - t.Fatal(err) - } - err = wait.For(func() (done bool, err error) { - err = crane.Push(src, fmt.Sprintf("%s/fn-labelizer:latest", reg), crane.Insecure) - if err != nil { - return false, nil //nolint:nilerr // we want to retry and to throw error - } - return true, nil - }, wait.WithTimeout(1*time.Minute)) - if err != nil { - t.Fatal("copying image to registry not successful", err) - } - return ctx - }). + WithSetup("CopyFnImageToRegistry", funcs.AllOf( + funcs.CopyImageToRegistry(clusterName, regNs, "private-docker-registry", "crossplane-e2e/fn-labelizer:latest", timeoutOne))). WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade( HelmOptions( @@ -161,7 +139,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). Assess("ManagedResourcesProcessedByFunction", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { labelName := "labelizer.xfn.crossplane.io/processed" rg := utils.NewResourceGetter(ctx, t, config) @@ -181,11 +159,10 @@ func TestXfnRunnerImagePull(t *testing.T) { return false, nil } return true, nil - }, wait.WithTimeout(5*time.Minute)) + }, wait.WithTimeout(timeoutFive)) if err != nil { t.Fatalf("Expected label %v value to be true", labelName) } - } return ctx }). @@ -204,7 +181,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), )). WithTeardown("RemoveRegistry", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.DeleteNamespace("reg")), + funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(regNs)), func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { client := config.Client().Resources(namespace) configMap := &corev1.ConfigMap{ @@ -235,7 +212,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { WithLabel(LabelArea, "xfn"). WithSetup("InstallRegistry", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.CreateNamespace("reg")), + funcs.AsFeaturesFunc(envfuncs.CreateNamespace(regNs)), funcs.AsFeaturesFunc( funcs.HelmRepo( helm.WithArgs("add"), @@ -245,7 +222,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.AsFeaturesFunc( funcs.HelmInstall( helm.WithName("public"), - helm.WithNamespace("reg"), + helm.WithNamespace(regNs), helm.WithWait(), helm.WithChart("twuni/docker-registry"), helm.WithVersion("2.2.2"), @@ -255,48 +232,8 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { ), ))), ). - WithSetup("CopyFnImageToRegistry", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - nodes := &corev1.NodeList{} - if err := config.Client().Resources().List(ctx, nodes); err != nil { - t.Fatal("cannot list nodes", err) - } - if len(nodes.Items) == 0 { - t.Fatalf("no nodes in the cluster") - } - - var addr string - for _, a := range nodes.Items[0].Status.Addresses { - if a.Type == corev1.NodeInternalIP { - addr = a.Address - break - } - } - if addr == "" { - t.Fatalf("no nodes with private address") - } - - srcRef, err := name.ParseReference("crossplane-e2e/fn-tmp-writer:latest") - if err != nil { - t.Fatal(err) - } - - src, err := daemon.Image(srcRef) - if err != nil { - t.Fatal(err) - } - - err = wait.For(func() (done bool, err error) { - err = crane.Push(src, fmt.Sprintf("%s:32000/fn-tmp-writer:latest", addr), crane.Insecure) - if err != nil { - return false, nil //nolint:nilerr // we want to retry and to throw error - } - return true, nil - }, wait.WithTimeout(1*time.Minute)) - if err != nil { - t.Fatal("copying image to registry not successful", err) - } - return ctx - }). + WithSetup("CopyFnImageToRegistry", funcs.AllOf( + funcs.CopyImageToRegistry(clusterName, regNs, "public-docker-registry", "crossplane-e2e/fn-tmp-writer:latest", timeoutOne))). WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade( HelmOptions( @@ -325,9 +262,9 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(5*time.Minute, manifests, "claim.yaml", xpv1.Available())). + Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). Assess("ManagedResourcesProcessedByFunction", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - annotationName := "lines" + annotationName := "tmp-write-access" rg := utils.NewResourceGetter(ctx, t, config) claim := rg.Get("fn-tmp-writer", "default", "nop.example.org/v1alpha1", "NopResource") r := utils.ResourceValue(t, claim, "spec", "resourceRef") @@ -341,13 +278,13 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { if !found { return false, nil } - if a != "finally!" { + if a != "true" { return false, nil } return true, nil }, wait.WithTimeout(5*time.Minute)) if err != nil { - t.Fatalf("Expected annottion %v value is `finally!`", annotationName) + t.Fatalf("Expected annottion %v value is `true`", annotationName) } } return ctx @@ -367,7 +304,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), )). WithTeardown("RemoveRegistry", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.DeleteNamespace("reg")), + funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(regNs)), )). WithTeardown("CrossplaneDeployedWithoutFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), From 0d74128ff0c2a857524e37601cb79f557444f23a Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Tue, 18 Jul 2023 18:39:39 +0300 Subject: [PATCH 102/148] introduce a new helper `ClaimsManagedResourcesHaveLabel` to reduce code duplication Signed-off-by: ezgidemirel --- test/e2e/funcs/feature.go | 33 +++++++++++ test/e2e/testdata/images/tmp-writer/writer.sh | 2 +- test/e2e/xfn_test.go | 55 +------------------ 3 files changed, 36 insertions(+), 54 deletions(-) diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index a1b01eece..91e71fd21 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -49,6 +49,8 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" + + "github.com/crossplane/crossplane/test/e2e/utils" ) // AllOf runs the supplied functions in order. @@ -423,6 +425,37 @@ func CopyImageToRegistry(clusterName, ns, sName, image string, timeout time.Dura } } +// ClaimsManagedResourcesHaveLabel fails a test if the managed resources +// created by the claim does not have the supplied value at the supplied label +// path within the supplied duration. +func ClaimsManagedResourcesHaveLabel(ns, apiVersion, kind, name, label, want string, timeout time.Duration) features.Func { + return func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { + rg := utils.NewResourceGetter(ctx, t, c) + claim := rg.Get(name, ns, apiVersion, kind) + r := utils.ResourceValue(t, claim, "spec", "resourceRef") + + xr := rg.Get(r["name"], ns, r["apiVersion"], r["kind"]) + mrefs := utils.ResourceSliceValue(t, xr, "spec", "resourceRefs") + for _, mref := range mrefs { + err := wait.For(func() (done bool, err error) { + mr := rg.Get(mref["name"], ns, mref["apiVersion"], mref["kind"]) + a, found := mr.GetLabels()[label] + if !found { + return false, nil + } + if a != want { + return false, nil + } + return true, nil + }, wait.WithTimeout(timeout)) + if err != nil { + t.Fatalf("Expected label %s value is `%s`", label, want) + } + } + return ctx + } +} + // asUnstructured turns an arbitrary runtime.Object into an *Unstructured. If // it's already a concrete *Unstructured it just returns it, otherwise it // round-trips it through JSON encoding. This is necessary because types that diff --git a/test/e2e/testdata/images/tmp-writer/writer.sh b/test/e2e/testdata/images/tmp-writer/writer.sh index 851ab397d..08ef0ea3c 100755 --- a/test/e2e/testdata/images/tmp-writer/writer.sh +++ b/test/e2e/testdata/images/tmp-writer/writer.sh @@ -2,4 +2,4 @@ touch "/tmp/foo.txt" || exit 1 -yq '(.desired.resources[] | .resource.metadata.annotations) |= {"tmp-write-access": "true"} + .' +yq '(.desired.resources[] | .resource.metadata.labels) |= {"tmp-writer.xfn.crossplane.io": "true"} + .' diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index ad9b76193..b8e825dfd 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -21,7 +21,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/e2e-framework/klient/wait" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" "sigs.k8s.io/e2e-framework/pkg/features" @@ -140,32 +139,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). - Assess("ManagedResourcesProcessedByFunction", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - labelName := "labelizer.xfn.crossplane.io/processed" - rg := utils.NewResourceGetter(ctx, t, config) - claim := rg.Get("fn-labelizer", "default", "nop.example.org/v1alpha1", "NopResource") - r := utils.ResourceValue(t, claim, "spec", "resourceRef") - - xr := rg.Get(r["name"], "default", r["apiVersion"], r["kind"]) - mrefs := utils.ResourceSliceValue(t, xr, "spec", "resourceRefs") - for _, mref := range mrefs { - err := wait.For(func() (done bool, err error) { - mr := rg.Get(mref["name"], "default", mref["apiVersion"], mref["kind"]) - l, found := mr.GetLabels()[labelName] - if !found { - return false, nil - } - if l != "true" { - return false, nil - } - return true, nil - }, wait.WithTimeout(timeoutFive)) - if err != nil { - t.Fatalf("Expected label %v value to be true", labelName) - } - } - return ctx - }). + Assess("ManagedResourcesProcessedByFunction", funcs.ClaimsManagedResourcesHaveLabel("default", "nop.example.org/v1alpha1", "NopResource", "fn-labelizer", "labelizer.xfn.crossplane.io/processed", "true", timeoutFive)). WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), @@ -263,32 +237,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). - Assess("ManagedResourcesProcessedByFunction", func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - annotationName := "tmp-write-access" - rg := utils.NewResourceGetter(ctx, t, config) - claim := rg.Get("fn-tmp-writer", "default", "nop.example.org/v1alpha1", "NopResource") - r := utils.ResourceValue(t, claim, "spec", "resourceRef") - - xr := rg.Get(r["name"], "default", r["apiVersion"], r["kind"]) - mrefs := utils.ResourceSliceValue(t, xr, "spec", "resourceRefs") - for _, mref := range mrefs { - err := wait.For(func() (done bool, err error) { - mr := rg.Get(mref["name"], "default", mref["apiVersion"], mref["kind"]) - a, found := mr.GetAnnotations()[annotationName] - if !found { - return false, nil - } - if a != "true" { - return false, nil - } - return true, nil - }, wait.WithTimeout(5*time.Minute)) - if err != nil { - t.Fatalf("Expected annottion %v value is `true`", annotationName) - } - } - return ctx - }). + Assess("ManagedResourcesProcessedByFunction", funcs.ClaimsManagedResourcesHaveLabel("default", "nop.example.org/v1alpha1", "NopResource", "fn-tmp-writer", "tmp-writer.xfn.crossplane.io", "true", timeoutFive)). WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), From 52363e4f047447bff88121a6ba47be6f4d901dae Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Wed, 19 Jul 2023 19:15:49 +0300 Subject: [PATCH 103/148] refactor helper to make it more generic Signed-off-by: ezgidemirel --- test/e2e/funcs/feature.go | 76 ++++++++++++++++++--------- test/e2e/utils/resources.go | 102 ------------------------------------ test/e2e/xfn_test.go | 16 +++--- 3 files changed, 59 insertions(+), 135 deletions(-) delete mode 100644 test/e2e/utils/resources.go diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index 91e71fd21..6e80fdde1 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -49,8 +49,8 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" - - "github.com/crossplane/crossplane/test/e2e/utils" + "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/claim" + "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composite" ) // AllOf runs the supplied functions in order. @@ -425,33 +425,59 @@ func CopyImageToRegistry(clusterName, ns, sName, image string, timeout time.Dura } } -// ClaimsManagedResourcesHaveLabel fails a test if the managed resources -// created by the claim does not have the supplied value at the supplied label -// path within the supplied duration. -func ClaimsManagedResourcesHaveLabel(ns, apiVersion, kind, name, label, want string, timeout time.Duration) features.Func { +// ManagedResourcesOfClaimHaveFieldValueWithin fails a test if the managed resources +// created by the claim does not have the supplied value at the supplied path +// within the supplied duration. +func ManagedResourcesOfClaimHaveFieldValueWithin(d time.Duration, dir, file, path string, want any) features.Func { return func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { - rg := utils.NewResourceGetter(ctx, t, c) - claim := rg.Get(name, ns, apiVersion, kind) - r := utils.ResourceValue(t, claim, "spec", "resourceRef") - - xr := rg.Get(r["name"], ns, r["apiVersion"], r["kind"]) - mrefs := utils.ResourceSliceValue(t, xr, "spec", "resourceRefs") - for _, mref := range mrefs { - err := wait.For(func() (done bool, err error) { - mr := rg.Get(mref["name"], ns, mref["apiVersion"], mref["kind"]) - a, found := mr.GetLabels()[label] - if !found { - return false, nil - } - if a != want { - return false, nil - } - return true, nil - }, wait.WithTimeout(timeout)) + cm := &claim.Unstructured{} + if err := decoder.DecodeFile(os.DirFS(dir), file, cm); err != nil { + t.Error(err) + return ctx + } + + if err := c.Client().Resources().Get(ctx, cm.GetName(), cm.GetNamespace(), cm); err != nil { + t.Errorf("cannot get claim %s: %v", cm.GetName(), err) + return ctx + } + + xrRef := cm.GetResourceReference() + uxr := &composite.Unstructured{} + + uxr.SetGroupVersionKind(xrRef.GroupVersionKind()) + if err := c.Client().Resources().Get(ctx, xrRef.Name, xrRef.Namespace, uxr); err != nil { + t.Errorf("cannot get composite %s: %v", xrRef.Name, err) + return ctx + } + + mrRefs := uxr.GetResourceReferences() + + list := &unstructured.UnstructuredList{} + for _, ref := range mrRefs { + mr := &unstructured.Unstructured{} + mr.SetName(ref.Name) + mr.SetNamespace(ref.Namespace) + mr.SetGroupVersionKind(ref.GroupVersionKind()) + list.Items = append(list.Items, *mr) + } + + match := func(o k8s.Object) bool { + u := asUnstructured(o) + got, err := fieldpath.Pave(u.Object).GetValue(path) if err != nil { - t.Fatalf("Expected label %s value is `%s`", label, want) + return false } + + return cmp.Equal(want, got) } + + if err := wait.For(conditions.New(c.Client().Resources()).ResourcesMatch(list, match), wait.WithTimeout(d)); err != nil { + y, _ := yaml.Marshal(list.Items) + t.Errorf("resources did not have desired conditions: %s: %v:\n\n%s\n\n", want, err, y) + return ctx + } + + t.Logf("%d resources have desired value %q at field path %s", len(list.Items), want, path) return ctx } } diff --git a/test/e2e/utils/resources.go b/test/e2e/utils/resources.go deleted file mode 100644 index 2e7a4ef2e..000000000 --- a/test/e2e/utils/resources.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright 2023 The Crossplane Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package utils - -import ( - "context" - "fmt" - "reflect" - "testing" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - cr "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/e2e-framework/pkg/envconf" -) - -// ResourceGetter retrieves arbitrary k8s objects -type ResourceGetter struct { - ctx context.Context - t *testing.T - config *envconf.Config -} - -// NewResourceGetter returns a new getter that can be used for retrieving k8s objects of arbitrary type -func NewResourceGetter(ctx context.Context, t *testing.T, config *envconf.Config) *ResourceGetter { - return &ResourceGetter{ - ctx: ctx, - t: t, - config: config, - } -} - -// Get returns k8s object for the given name, namespace, apiVersion and kind -// if the requested object does not exist, the test fails -func (r *ResourceGetter) Get(name string, namespace string, apiVersion string, kind string) *unstructured.Unstructured { - client := r.config.Client().Resources().GetControllerRuntimeClient() - u := &unstructured.Unstructured{} - gv, err := schema.ParseGroupVersion(apiVersion) - if err != nil { - r.t.Fatal(err) - } - u.SetGroupVersionKind(gv.WithKind(kind)) - if err := client.Get(r.ctx, cr.ObjectKey{Name: name, Namespace: namespace}, u); err != nil { - r.t.Fatal("cannot get claim", err) - } - return u -} - -// ResourceValue returns the value of field on the given path -// in case of error or if the field does not exist, the test fails -func ResourceValue(t *testing.T, u *unstructured.Unstructured, path ...string) map[string]string { - f, found, err := unstructured.NestedStringMap(u.Object, path...) - if err != nil { - t.Fatal(err) - } - if !found { - t.Fatalf("field not found at path %v", path) - } - return f -} - -// ResourceSliceValue returns the slice value of field on the given path -// in case of error or if the field does not exist, the test fails -func ResourceSliceValue(t *testing.T, u *unstructured.Unstructured, path ...string) []map[string]string { - f, found, err := unstructured.NestedSlice(u.Object, path...) - if err != nil { - t.Fatal(err) - } - if !found { - t.Fatalf("field not found at path %v", path) - } - var s []map[string]string - for _, v := range f { - if vv, ok := v.(map[string]interface{}); ok { - s = append(s, asMapOfStrings(vv)) - } else { - t.Fatalf("not a map[string]string: %v type %s", v, reflect.TypeOf(v)) - } - } - return s -} - -func asMapOfStrings(m map[string]interface{}) map[string]string { - r := make(map[string]string) - for k, v := range m { - r[k] = fmt.Sprintf("%v", v) - } - return r -} diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index b8e825dfd..ee0d179e3 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -139,7 +139,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). - Assess("ManagedResourcesProcessedByFunction", funcs.ClaimsManagedResourcesHaveLabel("default", "nop.example.org/v1alpha1", "NopResource", "fn-labelizer", "labelizer.xfn.crossplane.io/processed", "true", timeoutFive)). + Assess("ManagedResourcesProcessedByFunction", funcs.ManagedResourcesOfClaimHaveFieldValueWithin(timeoutFive, manifests, "claim.yaml", "metadata.labels[labelizer.xfn.crossplane.io/processed]", "true")). WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), @@ -206,8 +206,8 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { ), ))), ). - WithSetup("CopyFnImageToRegistry", funcs.AllOf( - funcs.CopyImageToRegistry(clusterName, regNs, "public-docker-registry", "crossplane-e2e/fn-tmp-writer:latest", timeoutOne))). + WithSetup("CopyFnImageToRegistry", + funcs.CopyImageToRegistry(clusterName, regNs, "public-docker-registry", "crossplane-e2e/fn-tmp-writer:latest", timeoutOne)). WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade( HelmOptions( @@ -236,8 +236,10 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.ApplyResources(FieldManager, manifests, "claim.yaml"), funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). - Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). - Assess("ManagedResourcesProcessedByFunction", funcs.ClaimsManagedResourcesHaveLabel("default", "nop.example.org/v1alpha1", "NopResource", "fn-tmp-writer", "tmp-writer.xfn.crossplane.io", "true", timeoutFive)). + Assess("ClaimBecomesAvailable", + funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). + Assess("ManagedResourcesProcessedByFunction", + funcs.ManagedResourcesOfClaimHaveFieldValueWithin(timeoutFive, manifests, "claim.yaml", "metadata.labels[tmp-writer.xfn.crossplane.io]", "true")). WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), @@ -252,9 +254,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), )). - WithTeardown("RemoveRegistry", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(regNs)), - )). + WithTeardown("RemoveRegistry", funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(regNs))). WithTeardown("CrossplaneDeployedWithoutFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), funcs.ReadyToTestWithin(1*time.Minute, namespace), From 0badac5702922441ffba52b51827555112b12a9c Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Thu, 20 Jul 2023 12:41:41 +0300 Subject: [PATCH 104/148] add filtering mechanism to ManagedResourcesOfClaimHaveFieldValueWithin helper Signed-off-by: ezgidemirel --- test/e2e/funcs/env.go | 10 +++---- test/e2e/funcs/feature.go | 27 ++++++++++++++++- .../private-registry/pull/composition.yaml | 2 +- .../xfnrunner/tmp-writer/composition.yaml | 2 +- test/e2e/xfn_test.go | 30 ++++++++++--------- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/test/e2e/funcs/env.go b/test/e2e/funcs/env.go index 363f4199f..46bc7f987 100644 --- a/test/e2e/funcs/env.go +++ b/test/e2e/funcs/env.go @@ -141,7 +141,7 @@ func ServiceIngressEndPoint(ctx context.Context, cfg *envconf.Config, clusterNam service := &corev1.Service{} err := client.Resources().Get(ctx, serviceName, namespace, service) if err != nil { - return "", err + return "", errors.Errorf("cannot get service %s/%s at cluster %s: %w", namespace, serviceName, clusterName, err) } var nodePort int32 @@ -157,21 +157,21 @@ func ServiceIngressEndPoint(ctx context.Context, cfg *envconf.Config, clusterNam if found { kindCfg, err := kindConfig(ctx, clusterName) if err != nil { - return "", err + return "", errors.Errorf("cannot get kind config for cluster %s: %w", clusterName, err) } hostPort, err := findHostPort(kindCfg, nodePort) if err != nil { - return "", err + return "", errors.Errorf("cannot find hostPort for nodePort %d in kind config for cluster %s: %w", nodePort, clusterName, err) } return fmt.Sprintf("localhost:%v", hostPort), nil } nodes := &corev1.NodeList{} if err := client.Resources().List(ctx, nodes); err != nil { - return "", errors.Wrap(err, "cannot list nodes") + return "", errors.Errorf("cannot list nodes for cluster %s: %w", clusterName, err) } addr, err := findAnyNodeIPAddress(nodes) if err != nil { - return "", err + return "", errors.Errorf("cannot find any node IP address for cluster %s: %w", clusterName, err) } return fmt.Sprintf("%s:%v", addr, nodePort), nil } diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index 6e80fdde1..3f5310e14 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -24,6 +24,7 @@ import ( "path/filepath" "reflect" "strings" + "sync/atomic" "testing" "time" @@ -36,6 +37,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/json" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/e2e-framework/klient/decoder" @@ -428,7 +430,7 @@ func CopyImageToRegistry(clusterName, ns, sName, image string, timeout time.Dura // ManagedResourcesOfClaimHaveFieldValueWithin fails a test if the managed resources // created by the claim does not have the supplied value at the supplied path // within the supplied duration. -func ManagedResourcesOfClaimHaveFieldValueWithin(d time.Duration, dir, file, path string, want any) features.Func { +func ManagedResourcesOfClaimHaveFieldValueWithin(d time.Duration, dir, file, path string, want any, filter func(object k8s.Object) bool) features.Func { return func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { cm := &claim.Unstructured{} if err := decoder.DecodeFile(os.DirFS(dir), file, cm); err != nil { @@ -461,7 +463,15 @@ func ManagedResourcesOfClaimHaveFieldValueWithin(d time.Duration, dir, file, pat list.Items = append(list.Items, *mr) } + count := atomic.Int32{} match := func(o k8s.Object) bool { + // filter function should return true if the object needs to be checked. e.g., if you want to check the field + // path of a VPC object, filter function should return true for VPC objects only. + if filter != nil && !filter(o) { + t.Logf("skipping resource %s/%s/%s due to filtering", o.GetNamespace(), o.GetName(), o.GetObjectKind().GroupVersionKind().String()) + return true + } + count.Add(1) u := asUnstructured(o) got, err := fieldpath.Pave(u.Object).GetValue(path) if err != nil { @@ -477,6 +487,11 @@ func ManagedResourcesOfClaimHaveFieldValueWithin(d time.Duration, dir, file, pat return ctx } + if count.Load() == 0 { + t.Errorf("there are no unfiltered referred managed resources to check") + return ctx + } + t.Logf("%d resources have desired value %q at field path %s", len(list.Items), want, path) return ctx } @@ -510,3 +525,13 @@ func identifier(o k8s.Object) string { } return fmt.Sprintf("%s %s/%s", k, o.GetNamespace(), o.GetName()) } + +// FilterByGK returns a filter function that returns true if the supplied object is of the supplied GroupKind. +func FilterByGK(gk schema.GroupKind) func(o k8s.Object) bool { + return func(o k8s.Object) bool { + if o.GetObjectKind() == nil { + return false + } + return o.GetObjectKind().GroupVersionKind().Group == gk.Group && o.GetObjectKind().GroupVersionKind().Kind == gk.Kind + } +} diff --git a/test/e2e/manifests/xfnrunner/private-registry/pull/composition.yaml b/test/e2e/manifests/xfnrunner/private-registry/pull/composition.yaml index f20c850fb..227484321 100644 --- a/test/e2e/manifests/xfnrunner/private-registry/pull/composition.yaml +++ b/test/e2e/manifests/xfnrunner/private-registry/pull/composition.yaml @@ -35,5 +35,5 @@ spec: - name: labelizer type: Container container: - image: private-docker-registry.reg.svc.cluster.local:5000/fn-labelizer:latest + image: private-docker-registry.xfn-registry.svc.cluster.local:5000/fn-labelizer:latest imagePullPolicy: Always \ No newline at end of file diff --git a/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml b/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml index 7f9675b5e..a283bd74f 100644 --- a/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml +++ b/test/e2e/manifests/xfnrunner/tmp-writer/composition.yaml @@ -35,5 +35,5 @@ spec: - name: tmp-writer type: Container container: - image: public-docker-registry.reg.svc.cluster.local:5000/fn-tmp-writer:latest + image: public-docker-registry.xfn-registry.svc.cluster.local:5000/fn-tmp-writer:latest imagePullPolicy: Always \ No newline at end of file diff --git a/test/e2e/xfn_test.go b/test/e2e/xfn_test.go index ee0d179e3..be22147f6 100644 --- a/test/e2e/xfn_test.go +++ b/test/e2e/xfn_test.go @@ -21,6 +21,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" "sigs.k8s.io/e2e-framework/pkg/features" @@ -34,7 +35,7 @@ import ( ) const ( - regNs = "reg" + registryNs = "xfn-registry" timeoutFive = 5 * time.Minute timeoutOne = 1 * time.Minute @@ -48,9 +49,9 @@ func TestXfnRunnerImagePull(t *testing.T) { WithLabel(LabelArea, "xfn"). WithSetup("InstallRegistryWithCustomTlsCertificate", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.CreateNamespace(regNs)), + funcs.AsFeaturesFunc(envfuncs.CreateNamespace(registryNs)), func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { - dnsName := "private-docker-registry.reg.svc.cluster.local" + dnsName := "private-docker-registry.xfn-registry.svc.cluster.local" caPem, keyPem, err := utils.CreateCert(dnsName) if err != nil { t.Fatal(err) @@ -59,7 +60,7 @@ func TestXfnRunnerImagePull(t *testing.T) { secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "reg-cert", - Namespace: regNs, + Namespace: registryNs, }, Type: corev1.SecretTypeTLS, StringData: map[string]string{ @@ -95,7 +96,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.AsFeaturesFunc( funcs.HelmInstall( helm.WithName("private"), - helm.WithNamespace(regNs), + helm.WithNamespace(registryNs), helm.WithWait(), helm.WithChart("twuni/docker-registry"), helm.WithVersion("2.2.2"), @@ -106,8 +107,8 @@ func TestXfnRunnerImagePull(t *testing.T) { ), ))), ). - WithSetup("CopyFnImageToRegistry", funcs.AllOf( - funcs.CopyImageToRegistry(clusterName, regNs, "private-docker-registry", "crossplane-e2e/fn-labelizer:latest", timeoutOne))). + WithSetup("CopyFnImageToRegistry", + funcs.CopyImageToRegistry(clusterName, registryNs, "private-docker-registry", "crossplane-e2e/fn-labelizer:latest", timeoutOne)). WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade( HelmOptions( @@ -139,7 +140,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ResourcesCreatedWithin(30*time.Second, manifests, "claim.yaml"), )). Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). - Assess("ManagedResourcesProcessedByFunction", funcs.ManagedResourcesOfClaimHaveFieldValueWithin(timeoutFive, manifests, "claim.yaml", "metadata.labels[labelizer.xfn.crossplane.io/processed]", "true")). + Assess("ManagedResourcesProcessedByFunction", funcs.ManagedResourcesOfClaimHaveFieldValueWithin(timeoutFive, manifests, "claim.yaml", "metadata.labels[labelizer.xfn.crossplane.io/processed]", "true", nil)). WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), @@ -155,7 +156,7 @@ func TestXfnRunnerImagePull(t *testing.T) { funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), )). WithTeardown("RemoveRegistry", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(regNs)), + funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(registryNs)), func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context { client := config.Client().Resources(namespace) configMap := &corev1.ConfigMap{ @@ -186,7 +187,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { WithLabel(LabelArea, "xfn"). WithSetup("InstallRegistry", funcs.AllOf( - funcs.AsFeaturesFunc(envfuncs.CreateNamespace(regNs)), + funcs.AsFeaturesFunc(envfuncs.CreateNamespace(registryNs)), funcs.AsFeaturesFunc( funcs.HelmRepo( helm.WithArgs("add"), @@ -196,7 +197,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.AsFeaturesFunc( funcs.HelmInstall( helm.WithName("public"), - helm.WithNamespace(regNs), + helm.WithNamespace(registryNs), helm.WithWait(), helm.WithChart("twuni/docker-registry"), helm.WithVersion("2.2.2"), @@ -207,7 +208,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { ))), ). WithSetup("CopyFnImageToRegistry", - funcs.CopyImageToRegistry(clusterName, regNs, "public-docker-registry", "crossplane-e2e/fn-tmp-writer:latest", timeoutOne)). + funcs.CopyImageToRegistry(clusterName, registryNs, "public-docker-registry", "crossplane-e2e/fn-tmp-writer:latest", timeoutOne)). WithSetup("CrossplaneDeployedWithFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade( HelmOptions( @@ -239,7 +240,8 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { Assess("ClaimBecomesAvailable", funcs.ResourcesHaveConditionWithin(timeoutFive, manifests, "claim.yaml", xpv1.Available())). Assess("ManagedResourcesProcessedByFunction", - funcs.ManagedResourcesOfClaimHaveFieldValueWithin(timeoutFive, manifests, "claim.yaml", "metadata.labels[tmp-writer.xfn.crossplane.io]", "true")). + funcs.ManagedResourcesOfClaimHaveFieldValueWithin(timeoutFive, manifests, "claim.yaml", "metadata.labels[tmp-writer.xfn.crossplane.io]", "true", + funcs.FilterByGK(schema.GroupKind{Group: "nop.crossplane.io", Kind: "NopResource"}))). WithTeardown("DeleteClaim", funcs.AllOf( funcs.DeleteResources(manifests, "claim.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "claim.yaml"), @@ -254,7 +256,7 @@ func TestXfnRunnerWriteToTmp(t *testing.T) { funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/provider.yaml"), funcs.ResourcesDeletedWithin(30*time.Second, manifests, "prerequisites/definition.yaml"), )). - WithTeardown("RemoveRegistry", funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(regNs))). + WithTeardown("RemoveRegistry", funcs.AsFeaturesFunc(envfuncs.DeleteNamespace(registryNs))). WithTeardown("CrossplaneDeployedWithoutFunctionsEnabled", funcs.AllOf( funcs.AsFeaturesFunc(funcs.HelmUpgrade(HelmOptions()...)), funcs.ReadyToTestWithin(1*time.Minute, namespace), From e44f73f2a73512671c5f6a25d4ad0ac193394657 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 13 Jul 2023 16:11:35 +0200 Subject: [PATCH 105/148] fix: max size of package parsed limited to 200MB Signed-off-by: Philippe Scorsolini --- internal/controller/pkg/revision/reconciler.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/controller/pkg/revision/reconciler.go b/internal/controller/pkg/revision/reconciler.go index 9eb95720b..a2069a18a 100644 --- a/internal/controller/pkg/revision/reconciler.go +++ b/internal/controller/pkg/revision/reconciler.go @@ -54,6 +54,8 @@ import ( const ( reconcileTimeout = 3 * time.Minute + // the max size of a package parsed by the parser + maxPackageSize = 200 << 20 // 100 MB ) const ( @@ -474,7 +476,13 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco } // Parse package contents. - pkg, err := r.parser.Parse(ctx, rc) + pkg, err := r.parser.Parse(ctx, struct { + io.Reader + io.Closer + }{ + Reader: io.LimitReader(rc, maxPackageSize), + Closer: rc, + }) // Wait until we finish writing to cache. Parser closes the reader. if err := <-cacheWrite; err != nil { // If we failed to cache we want to cleanup, but we don't abort unless From b7d7d44ccd77ed9e1ce23ac133703b744b0b94eb Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Fri, 21 Jul 2023 09:39:40 +0200 Subject: [PATCH 106/148] fix: properly handle annotations schema aware validation Signed-off-by: Philippe Scorsolini --- pkg/validation/apiextensions/v1/composition/patches.go | 5 ++++- .../apiextensions/v1/composition/patches_test.go | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/validation/apiextensions/v1/composition/patches.go b/pkg/validation/apiextensions/v1/composition/patches.go index df81c238d..c85965110 100644 --- a/pkg/validation/apiextensions/v1/composition/patches.go +++ b/pkg/validation/apiextensions/v1/composition/patches.go @@ -399,7 +399,7 @@ func validateFieldPathSegment(parent *apiextensions.JSONSchemaProps, segment fie return nil, nil } -func validateFieldPathSegmentField(parent *apiextensions.JSONSchemaProps, segment fieldpath.Segment) (*apiextensions.JSONSchemaProps, error) { +func validateFieldPathSegmentField(parent *apiextensions.JSONSchemaProps, segment fieldpath.Segment) (*apiextensions.JSONSchemaProps, error) { //nolint:gocyclo // inherently complex if parent == nil { return nil, nil } @@ -420,6 +420,9 @@ func validateFieldPathSegmentField(parent *apiextensions.JSONSchemaProps, segmen // Schema is not nil. // See https://github.com/kubernetes/kubernetes/blob/ff4eff24ac4fad5431aa89681717d6c4fe5733a4/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go#L828 if parent.AdditionalProperties != nil && (parent.AdditionalProperties.Allows || parent.AdditionalProperties.Schema != nil) { + if parent.AdditionalProperties.Schema != nil && parent.AdditionalProperties.Schema.Type != "" { + return parent.AdditionalProperties.Schema, nil + } // re-evaluate the segment against the additional properties schema return validateFieldPathSegmentField(parent.AdditionalProperties.Schema, segment) } diff --git a/pkg/validation/apiextensions/v1/composition/patches_test.go b/pkg/validation/apiextensions/v1/composition/patches_test.go index b00b4e747..114c5f4dc 100644 --- a/pkg/validation/apiextensions/v1/composition/patches_test.go +++ b/pkg/validation/apiextensions/v1/composition/patches_test.go @@ -460,6 +460,13 @@ func TestValidateFieldPath(t *testing.T) { }, }}}}, }, + "AcceptAnnotations": { + want: want{err: nil, fieldType: "string"}, + args: args{ + fieldPath: "metadata.annotations[cooler-field]", + schema: getDefaultSchema(), + }, + }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { From 3a967336216d07473b667378afbe974bd6625dd8 Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Fri, 21 Jul 2023 12:36:30 +0300 Subject: [PATCH 107/148] empty commit for 1.13 Signed-off-by: ezgidemirel From 03b1b4b34eaf5da132c279a1d07689b9b2440c50 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Fri, 21 Jul 2023 15:21:41 +0200 Subject: [PATCH 108/148] fix: omitempty environmentConfigs label selector fields Signed-off-by: Philippe Scorsolini --- apis/apiextensions/v1/composition_environment.go | 6 +++--- .../v1beta1/zz_generated.composition_environment.go | 6 +++--- .../apiextensions.crossplane.io_compositionrevisions.yaml | 6 ------ cluster/crds/apiextensions.crossplane.io_compositions.yaml | 3 --- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/apis/apiextensions/v1/composition_environment.go b/apis/apiextensions/v1/composition_environment.go index b402601dd..ab63c773c 100644 --- a/apis/apiextensions/v1/composition_environment.go +++ b/apis/apiextensions/v1/composition_environment.go @@ -182,14 +182,14 @@ type EnvironmentSourceSelector struct { // Mode specifies retrieval strategy: "Single" or "Multiple". // +kubebuilder:validation:Enum=Single;Multiple // +kubebuilder:default=Single - Mode EnvironmentSourceSelectorModeType `json:"mode"` + Mode EnvironmentSourceSelectorModeType `json:"mode,omitempty"` // MaxMatch specifies the number of extracted EnvironmentConfigs in Multiple mode, extracts all if nil. MaxMatch *uint64 `json:"maxMatch,omitempty"` // SortByFieldPath is the path to the field based on which list of EnvironmentConfigs is alphabetically sorted. // +kubebuilder:default="metadata.name" - SortByFieldPath string `json:"sortByFieldPath"` + SortByFieldPath string `json:"sortByFieldPath,omitempty"` // MatchLabels ensures an object with matching labels is selected. MatchLabels []EnvironmentSourceSelectorLabelMatcher `json:"matchLabels,omitempty"` @@ -231,7 +231,7 @@ type EnvironmentSourceSelectorLabelMatcher struct { // +optional // +kubebuilder:validation:Enum=FromCompositeFieldPath;Value // +kubebuilder:default=FromCompositeFieldPath - Type EnvironmentSourceSelectorLabelMatcherType `json:"type"` + Type EnvironmentSourceSelectorLabelMatcherType `json:"type,omitempty"` // Key of the label to match. Key string `json:"key"` diff --git a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go index 01f26f0fb..fb3a2d7f4 100644 --- a/apis/apiextensions/v1beta1/zz_generated.composition_environment.go +++ b/apis/apiextensions/v1beta1/zz_generated.composition_environment.go @@ -184,14 +184,14 @@ type EnvironmentSourceSelector struct { // Mode specifies retrieval strategy: "Single" or "Multiple". // +kubebuilder:validation:Enum=Single;Multiple // +kubebuilder:default=Single - Mode EnvironmentSourceSelectorModeType `json:"mode"` + Mode EnvironmentSourceSelectorModeType `json:"mode,omitempty"` // MaxMatch specifies the number of extracted EnvironmentConfigs in Multiple mode, extracts all if nil. MaxMatch *uint64 `json:"maxMatch,omitempty"` // SortByFieldPath is the path to the field based on which list of EnvironmentConfigs is alphabetically sorted. // +kubebuilder:default="metadata.name" - SortByFieldPath string `json:"sortByFieldPath"` + SortByFieldPath string `json:"sortByFieldPath,omitempty"` // MatchLabels ensures an object with matching labels is selected. MatchLabels []EnvironmentSourceSelectorLabelMatcher `json:"matchLabels,omitempty"` @@ -233,7 +233,7 @@ type EnvironmentSourceSelectorLabelMatcher struct { // +optional // +kubebuilder:validation:Enum=FromCompositeFieldPath;Value // +kubebuilder:default=FromCompositeFieldPath - Type EnvironmentSourceSelectorLabelMatcherType `json:"type"` + Type EnvironmentSourceSelectorLabelMatcherType `json:"type,omitempty"` // Key of the label to match. Key string `json:"key"` diff --git a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml index 9de2b4e82..d9947e7f2 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml @@ -147,9 +147,6 @@ spec: based on which list of EnvironmentConfigs is alphabetically sorted. type: string - required: - - mode - - sortByFieldPath type: object type: default: Reference @@ -1628,9 +1625,6 @@ spec: based on which list of EnvironmentConfigs is alphabetically sorted. type: string - required: - - mode - - sortByFieldPath type: object type: default: Reference diff --git a/cluster/crds/apiextensions.crossplane.io_compositions.yaml b/cluster/crds/apiextensions.crossplane.io_compositions.yaml index 18af910dd..aaf2bcd3f 100644 --- a/cluster/crds/apiextensions.crossplane.io_compositions.yaml +++ b/cluster/crds/apiextensions.crossplane.io_compositions.yaml @@ -144,9 +144,6 @@ spec: based on which list of EnvironmentConfigs is alphabetically sorted. type: string - required: - - mode - - sortByFieldPath type: object type: default: Reference From 25e87502e3611f56fe40ff121f683fb051db7c5a Mon Sep 17 00:00:00 2001 From: Carlos Santana Date: Fri, 30 Jun 2023 15:56:49 -0400 Subject: [PATCH 109/148] Add SIG info in readme Signed-off-by: Carlos Santana --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index e16eed8fc..f45980781 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,18 @@ with the broader community is encouraged to join. * [Past meeting recordings] * [Community Calendar][community calendar] +### Special Interest Groups (SIG) +Each SIG collaborates in Slack and some groups have regular meetings, you can find the meetings in the [Community Calendar][community calendar]. +- [#sig-composition-environments][sig-composition-environments-slack] +- [#sig-composition-functions][sig-composition-functions-slack] +- [#sig-e2e-testing][sig-e2e-testing-slack] +- [#sig-observe-only][sig-observe-only-slack] +- [#sig-provider-families][sig-provider-families-slack] +- [#sig-secret-stores][sig-secret-stores-slack] +- [#sig-deletion-ordering][sig-deletion-ordering-slack] +- [#sig-upjet-provider-resource-utilization][sig-upjet-provider-resource-utilization-slack] + + ## Adopters A list of publicly known users of the Crossplane project can be found in [ADOPTERS.md]. We @@ -96,3 +108,11 @@ Crossplane is under the Apache 2.0 license. [releases]: https://github.com/crossplane/crossplane/releases [ADOPTERS.md]: ADOPTERS.md [Crossplane Roadmap]: https://github.com/orgs/crossplane/projects/20/views/3?pane=info +[sig-composition-environments-slack]: https://crossplane.slack.com/archives/C05BP6QFLUW +[sig-composition-functions-slack]: https://crossplane.slack.com/archives/C031Y29CSAE +[sig-e2e-testing-slack]: https://crossplane.slack.com/archives/C05C8CCTVNV +[sig-observe-only-slack]: https://crossplane.slack.com/archives/C04D5988QEA +[sig-provider-families-slack]: https://crossplane.slack.com/archives/C056YAQRV16 +[sig-secret-stores-slack]: https://crossplane.slack.com/archives/C05BY7DKFV2 +[sig-deletion-ordering-slack]: https://crossplane.slack.com/archives/C05BP8W5ALW +[sig-upjet-provider-resource-utilization-slack]: https://crossplane.slack.com/archives/C04QLETDJGN From 7515f96f1f31042c91900bd9053e6db1f74d11e7 Mon Sep 17 00:00:00 2001 From: Carlos Santana Date: Fri, 21 Jul 2023 19:14:48 +0000 Subject: [PATCH 110/148] wrap line at 80 Signed-off-by: Carlos Santana --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f45980781..013077ef4 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,8 @@ with the broader community is encouraged to join. * [Community Calendar][community calendar] ### Special Interest Groups (SIG) -Each SIG collaborates in Slack and some groups have regular meetings, you can find the meetings in the [Community Calendar][community calendar]. +Each SIG collaborates in Slack and some groups have regular meetings, you can +find the meetings in the [Community Calendar][community calendar]. - [#sig-composition-environments][sig-composition-environments-slack] - [#sig-composition-functions][sig-composition-functions-slack] - [#sig-e2e-testing][sig-e2e-testing-slack] From 4feb58e7b6f8a30d1fc311f6169855465577e3f2 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 13 Jul 2023 14:39:00 +0200 Subject: [PATCH 111/148] fix: validate Package images against manifest on pull Signed-off-by: Philippe Scorsolini --- internal/controller/pkg/revision/imageback.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/controller/pkg/revision/imageback.go b/internal/controller/pkg/revision/imageback.go index bbad98662..dea27e366 100644 --- a/internal/controller/pkg/revision/imageback.go +++ b/internal/controller/pkg/revision/imageback.go @@ -23,6 +23,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/validate" "github.com/crossplane/crossplane-runtime/pkg/errors" "github.com/crossplane/crossplane-runtime/pkg/parser" @@ -40,6 +41,8 @@ const ( errMultipleAnnotatedLayers = "package is invalid due to multiple annotated base layers" errOpenPackageStream = "failed to open package stream file" errFmtMaxManifestLayers = "package has %d layers, but only %d are allowed" + errValidateLayer = "invalid package layer" + errValidateImage = "invalid package image" ) const ( @@ -130,6 +133,9 @@ func (i *ImageBackend) Init(ctx context.Context, bo ...parser.BackendOption) (io if err != nil { return nil, errors.Wrap(err, errFetchLayer) } + if err := validate.Layer(layer); err != nil { + return nil, errors.Wrap(err, errValidateLayer) + } tarc, err = layer.Uncompressed() if err != nil { return nil, errors.Wrap(err, errGetUncompressed) @@ -138,6 +144,9 @@ func (i *ImageBackend) Init(ctx context.Context, bo ...parser.BackendOption) (io // If we still don't have content then we need to flatten image filesystem. if !foundAnnotated { + if err := validate.Image(img); err != nil { + return nil, errors.Wrap(err, errValidateImage) + } tarc = mutate.Extract(img) } From 2c3db49a3967de74fbd983f8fc6e1237b8956417 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Mon, 24 Jul 2023 19:25:40 +0200 Subject: [PATCH 112/148] tests: remove successfull package fetch test case Signed-off-by: Philippe Scorsolini --- .../controller/pkg/revision/imageback_test.go | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/internal/controller/pkg/revision/imageback_test.go b/internal/controller/pkg/revision/imageback_test.go index add68a80f..d1f6a1617 100644 --- a/internal/controller/pkg/revision/imageback_test.go +++ b/internal/controller/pkg/revision/imageback_test.go @@ -17,18 +17,14 @@ limitations under the License. package revision import ( - "archive/tar" - "bytes" "context" "io" - "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" - "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/crossplane/crossplane-runtime/pkg/errors" @@ -57,23 +53,24 @@ func TestImageBackend(t *testing.T) { }, }) - streamCont := "somestreamofyaml" - tarBuf := new(bytes.Buffer) - tw := tar.NewWriter(tarBuf) - hdr := &tar.Header{ - Name: xpkg.StreamFile, - Mode: int64(xpkg.StreamFileMode), - Size: int64(len(streamCont)), - } - _ = tw.WriteHeader(hdr) - _, _ = io.Copy(tw, strings.NewReader(streamCont)) - _ = tw.Close() - packLayer, _ := tarball.LayerFromOpener(func() (io.ReadCloser, error) { - // NOTE(hasheddan): we must construct a new reader each time as we - // ingest packImg in multiple tests below. - return io.NopCloser(bytes.NewReader(tarBuf.Bytes())), nil - }) - packImg, _ := mutate.AppendLayers(empty.Image, packLayer) + // TODO(phisco): uncomment when https://github.com/google/go-containerregistry/pull/1758 is merged + // streamCont := "somestreamofyaml" + // tarBuf := new(bytes.Buffer) + // tw := tar.NewWriter(tarBuf) + // hdr := &tar.Header{ + // Name: xpkg.StreamFile, + // Mode: int64(xpkg.StreamFileMode), + // Size: int64(len(streamCont)), + // } + // _ = tw.WriteHeader(hdr) + // _, _ = io.Copy(tw, strings.NewReader(streamCont)) + // _ = tw.Close() + // packLayer, _ := tarball.LayerFromOpener(func() (io.ReadCloser, error) { + // // NOTE(hasheddan): we must construct a new reader each time as we + // // ingest packImg in multiple tests below. + // return io.NopCloser(bytes.NewReader(tarBuf.Bytes())), nil + // }) + // packImg, _ := mutate.AppendLayers(empty.Image, packLayer) type args struct { f xpkg.Fetcher @@ -152,19 +149,20 @@ func TestImageBackend(t *testing.T) { }, want: errors.Wrap(errBoom, errFetchPackage), }, - "SuccessFetchPackage": { - reason: "Should not return error is package is not in cache but is fetched successfully.", - args: args{ - f: &fake.MockFetcher{ - MockFetch: fake.NewMockFetchFn(packImg, nil), - }, - opts: []parser.BackendOption{PackageRevision(&v1.ProviderRevision{ - Spec: v1.PackageRevisionSpec{ - Package: "test/test:latest", - }, - })}, - }, - }, + // TODO(phisco): uncomment when https://github.com/google/go-containerregistry/pull/1758 is merged + // "SuccessFetchPackage": { + // reason: "Should not return error is package is not in cache but is fetched successfully.", + // args: args{ + // f: &fake.MockFetcher{ + // MockFetch: fake.NewMockFetchFn(packImg, nil), + // }, + // opts: []parser.BackendOption{PackageRevision(&v1.ProviderRevision{ + // Spec: v1.PackageRevisionSpec{ + // Package: "test/test:latest", + // }, + // })}, + // }, + // }, } for name, tc := range cases { From 7c9bab1b26baa6808bdcd5a782abc409084d82ef Mon Sep 17 00:00:00 2001 From: Matt Bush Date: Mon, 24 Jul 2023 15:59:20 -0700 Subject: [PATCH 113/148] tests that fail because of #4129 Signed-off-by: Matt Bush --- internal/xcrd/crd_test.go | 42 ++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index fe17dd676..2cea4757d 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -87,6 +87,7 @@ func TestForCompositeResource(t *testing.T) { ], "properties": { "spec": { + "description": "Specification of the resource.", "required": [ "storageGB", "engineVersion" @@ -100,7 +101,8 @@ func TestForCompositeResource(t *testing.T) { "type": "string" }, "storageGB": { - "type": "integer" + "type": "integer", + "description": "Pretend this is useful." } }, "type": "object" @@ -111,10 +113,12 @@ func TestForCompositeResource(t *testing.T) { "type": "string" } }, - "type": "object" + "type": "object", + "description": "Status of the resource." } }, - "type": "object" + "type": "object", + "description": "What the resource is for." }` d := &v1.CompositeResourceDefinition{ @@ -193,6 +197,7 @@ func TestForCompositeResource(t *testing.T) { Schema: &extv1.CustomResourceValidation{ OpenAPIV3Schema: &extv1.JSONSchemaProps{ Type: "object", + Description: "What the resource is for.", Required: []string{"spec"}, Properties: map[string]extv1.JSONSchemaProps{ "apiVersion": { @@ -209,9 +214,10 @@ func TestForCompositeResource(t *testing.T) { "spec": { Type: "object", Required: []string{"storageGB", "engineVersion"}, + Description: "Specification of the resource.", Properties: map[string]extv1.JSONSchemaProps{ // From CRDSpecTemplate.Validation - "storageGB": {Type: "integer"}, + "storageGB": {Type: "integer", Description: "Pretend this is useful."}, "engineVersion": { Type: "string", Enum: []extv1.JSON{ @@ -356,6 +362,7 @@ func TestForCompositeResource(t *testing.T) { }, "status": { Type: "object", + Description: "Status of the resource.", Properties: map[string]extv1.JSONSchemaProps{ "phase": {Type: "string"}, @@ -522,6 +529,7 @@ func TestForCompositeResourceClaim(t *testing.T) { { "properties": { "spec": { + "description": "Specification of the resource.", "required": [ "storageGB", "engineVersion" @@ -535,21 +543,24 @@ func TestForCompositeResourceClaim(t *testing.T) { "type": "string" }, "storageGB": { - "type": "integer" + "type": "integer", + "description": "Pretend this is useful." } }, "type": "object" }, "status": { - "properties": { - "phase": { - "type": "string" - } - }, - "type": "object" - } + "properties": { + "phase": { + "type": "string" + } + }, + "type": "object", + "description": "Status of the resource." + } }, - "type": "object" + "type": "object", + "description": "Description of the resource." }` d := &v1.CompositeResourceDefinition{ @@ -636,6 +647,7 @@ func TestForCompositeResourceClaim(t *testing.T) { OpenAPIV3Schema: &extv1.JSONSchemaProps{ Type: "object", Required: []string{"spec"}, + Description: "Description of the resource.", Properties: map[string]extv1.JSONSchemaProps{ "apiVersion": { Type: "string", @@ -651,9 +663,10 @@ func TestForCompositeResourceClaim(t *testing.T) { "spec": { Type: "object", Required: []string{"storageGB", "engineVersion"}, + Description: "Specification of the resource.", Properties: map[string]extv1.JSONSchemaProps{ // From CRDSpecTemplate.Validation - "storageGB": {Type: "integer"}, + "storageGB": {Type: "integer", Description: "Pretend this is useful."}, "engineVersion": { Type: "string", Enum: []extv1.JSON{ @@ -772,6 +785,7 @@ func TestForCompositeResourceClaim(t *testing.T) { }, "status": { Type: "object", + Description: "Status of the resource.", Properties: map[string]extv1.JSONSchemaProps{ "phase": {Type: "string"}, From 0cd9fd320f7671f60c07bf4a5473e684e6f7c6b3 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Tue, 25 Jul 2023 12:59:04 +0100 Subject: [PATCH 114/148] composite: fix nil-dereference Signed-off-by: AdamKorcz --- .../apiextensions/composite/composition_transforms.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/controller/apiextensions/composite/composition_transforms.go b/internal/controller/apiextensions/composite/composition_transforms.go index 0b411e469..48f6c2651 100644 --- a/internal/controller/apiextensions/composite/composition_transforms.go +++ b/internal/controller/apiextensions/composite/composition_transforms.go @@ -194,7 +194,14 @@ func ResolveMap(t v1.MapTransform, input any) (any, error) { } return val, nil default: - return nil, errors.Errorf(errFmtMapTypeNotSupported, reflect.TypeOf(input).String()) + var inputType string + if input == nil { + inputType = "nil" + } else { + inputType = reflect.TypeOf(input).String() + } + + return nil, errors.Errorf(errFmtMapTypeNotSupported, inputType) } } From 4db45cdc17079c5f03f5a67cb48a0e7e4ec9b3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel=20Ducanto=20Hadad?= Date: Wed, 26 Jul 2023 17:15:26 +0200 Subject: [PATCH 115/148] Add failing test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miguel Ángel Ducanto Hadad --- .../apiextensions/claim/configurator_test.go | 245 ++++++++++++++++-- 1 file changed, 217 insertions(+), 28 deletions(-) diff --git a/internal/controller/apiextensions/claim/configurator_test.go b/internal/controller/apiextensions/claim/configurator_test.go index 526f3f267..976f91eaf 100644 --- a/internal/controller/apiextensions/claim/configurator_test.go +++ b/internal/controller/apiextensions/claim/configurator_test.go @@ -372,6 +372,222 @@ func TestCompositeConfigure(t *testing.T) { }, }, }, + "UpdatePolicyAutomatic": { + reason: "CompositionRevision of composite should NOT be set by the claim", + args: args{ + cm: &claim.Unstructured{ + Unstructured: unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]any{ + "namespace": ns, + "name": name, + }, + "spec": map[string]any{ + "resourceRef": "ref", + "writeConnectionSecretToRef": "ref", + "compositionUpdatePolicy": "Automatic", + "compositionRevisionRef": map[string]any{ + "name": "newref", + }, + }, + "status": map[string]any{ + "previousCoolness": 23, + "conditions": []map[string]any{ + { + "type": "someCondition", + }, + }, + }, + }, + }, + }, + cp: &composite.Unstructured{ + Unstructured: unstructured.Unstructured{ + Object: map[string]any{ + "metadata": map[string]any{ + "namespace": ns, + "name": name + "-12345", + "creationTimestamp": func() string { + b, _ := now.MarshalJSON() + return strings.Trim(string(b), "\"") + }(), + "labels": map[string]any{ + xcrd.LabelKeyClaimNamespace: ns, + xcrd.LabelKeyClaimName: name, + }, + }, + "spec": map[string]any{ + "compositionUpdatePolicy": "Automatic", + "claimRef": map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "namespace": ns, + "name": name, + }, + }, + "status": map[string]any{ + "previousCoolness": 28, + "conditions": []map[string]any{ + { + "type": "otherCondition", + }, + }, + }, + }, + }, + }, + }, + want: want{ + cp: &composite.Unstructured{ + Unstructured: unstructured.Unstructured{ + Object: map[string]any{ + "metadata": map[string]any{ + "namespace": ns, + "name": name + "-12345", + "creationTimestamp": func() string { + b, _ := now.MarshalJSON() + return strings.Trim(string(b), "\"") + }(), + "labels": map[string]any{ + xcrd.LabelKeyClaimNamespace: ns, + xcrd.LabelKeyClaimName: name, + }, + }, + "spec": map[string]any{ + "compositionUpdatePolicy": "Automatic", + "claimRef": map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "namespace": ns, + "name": name, + }, + }, + "status": map[string]any{ + "previousCoolness": 28, + "conditions": []map[string]any{ + { + "type": "otherCondition", + }, + }, + }, + }, + }, + }, + }, + }, + "UpdatePolicyManual": { + reason: "CompositionRevision of composite should be overwritten by the claim", + args: args{ + cm: &claim.Unstructured{ + Unstructured: unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "metadata": map[string]any{ + "namespace": ns, + "name": name, + }, + "spec": map[string]any{ + "resourceRef": "ref", + "writeConnectionSecretToRef": "ref", + "compositionUpdatePolicy": "Manual", + "compositionRevisionRef": map[string]any{ + "name": "newref", + }, + }, + "status": map[string]any{ + "previousCoolness": 23, + "conditions": []map[string]any{ + { + "type": "someCondition", + }, + }, + }, + }, + }, + }, + cp: &composite.Unstructured{ + Unstructured: unstructured.Unstructured{ + Object: map[string]any{ + "metadata": map[string]any{ + "namespace": ns, + "name": name + "-12345", + "creationTimestamp": func() string { + b, _ := now.MarshalJSON() + return strings.Trim(string(b), "\"") + }(), + "labels": map[string]any{ + xcrd.LabelKeyClaimNamespace: ns, + xcrd.LabelKeyClaimName: name, + }, + }, + "spec": map[string]any{ + "compositionUpdatePolicy": "Manual", + "compositionRevisionRef": map[string]any{ + "name": "oldref", + }, + "claimRef": map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "namespace": ns, + "name": name, + }, + }, + "status": map[string]any{ + "previousCoolness": 28, + "conditions": []map[string]any{ + { + "type": "otherCondition", + }, + }, + }, + }, + }, + }, + }, + want: want{ + cp: &composite.Unstructured{ + Unstructured: unstructured.Unstructured{ + Object: map[string]any{ + "metadata": map[string]any{ + "namespace": ns, + "name": name + "-12345", + "creationTimestamp": func() string { + b, _ := now.MarshalJSON() + return strings.Trim(string(b), "\"") + }(), + "labels": map[string]any{ + xcrd.LabelKeyClaimNamespace: ns, + xcrd.LabelKeyClaimName: name, + }, + }, + "spec": map[string]any{ + "compositionUpdatePolicy": "Manual", + "compositionRevisionRef": map[string]any{ + "name": "newref", + }, + "claimRef": map[string]any{ + "apiVersion": apiVersion, + "kind": kind, + "namespace": ns, + "name": name, + }, + }, + "status": map[string]any{ + "previousCoolness": 28, + "conditions": []map[string]any{ + { + "type": "otherCondition", + }, + }, + }, + }, + }, + }, + }, + }, } for name, tc := range cases { @@ -403,7 +619,6 @@ func TestClaimConfigure(t *testing.T) { type want struct { cm resource.CompositeClaim err error - cp resource.Composite } cases := map[string]struct { @@ -727,7 +942,7 @@ func TestClaimConfigure(t *testing.T) { }, }, "UpdatePolicyManual": { - reason: "CompositionRevision of composite should be overwritten by the claim", + reason: "CompositionRevision of claim should NOT overwritten by the composite", args: args{ client: test.NewMockClient(), cm: &claim.Unstructured{ @@ -810,32 +1025,6 @@ func TestClaimConfigure(t *testing.T) { }, }, }, - cp: &composite.Unstructured{ - Unstructured: unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "namespace": ns, - "name": name + "-12345", - }, - "spec": map[string]any{ - "resourceRefs": "ref", - "claimRef": "ref", - "compositionUpdatePolicy": "Manual", - "compositionRevisionRef": map[string]any{ - "name": "oldref", - }, - }, - "status": map[string]any{ - "previousCoolness": 28, - "conditions": []map[string]any{ - { - "type": "otherCondition", - }, - }, - }, - }, - }, - }, }, }, "UpdatePolicyAutomatic": { From 2638840af589a0920a6fb3d73aa57994b357309c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel=20Ducanto=20Hadad?= Date: Wed, 26 Jul 2023 17:23:38 +0200 Subject: [PATCH 116/148] do not filter out compositionRevisionRef is updatePolicy is Manual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miguel Ángel Ducanto Hadad --- internal/controller/apiextensions/claim/configurator.go | 5 +++-- internal/xcrd/schemas.go | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/controller/apiextensions/claim/configurator.go b/internal/controller/apiextensions/claim/configurator.go index 4ed4807fb..5f36b530f 100644 --- a/internal/controller/apiextensions/claim/configurator.go +++ b/internal/controller/apiextensions/claim/configurator.go @@ -121,9 +121,10 @@ func (c *APIDryRunCompositeConfigurator) Configure(ctx context.Context, cm resou // CompositionRevision is a special field which needs to be propagated // based on the Update policy. If the policy is `Manual`, we need to - // overwrite the composite's value with the claim's + // remove CompositionRevisionRef from wellKnownClaimFields, so it + // does not get filtered out and is set correctly in composite if cp.GetCompositionUpdatePolicy() != nil && *cp.GetCompositionUpdatePolicy() == xpv1.UpdateManual { - cp.SetCompositionRevisionReference(cm.GetCompositionRevisionReference()) + delete(wellKnownClaimFields, xcrd.CompositionRevisionRef) } claimSpecFilter := xcrd.GetPropFields(wellKnownClaimFields) diff --git a/internal/xcrd/schemas.go b/internal/xcrd/schemas.go index 09ac176b2..29cd074ba 100644 --- a/internal/xcrd/schemas.go +++ b/internal/xcrd/schemas.go @@ -25,6 +25,9 @@ const ( LabelKeyClaimNamespace = "crossplane.io/claim-namespace" ) +// CompositionRevisionRef should be propagated dynamically +var CompositionRevisionRef = "compositionRevisionRef" + // PropagateSpecProps is the list of XRC spec properties to propagate // when translating an XRC into an XR and vice-versa. var PropagateSpecProps = []string{"compositionRef", "compositionSelector", "compositionUpdatePolicy", "compositionRevisionSelector"} From 686e8f8c067751fcd9d938ce229c29b9573a9296 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 20:23:35 +0000 Subject: [PATCH 117/148] Update module google.golang.org/grpc to v1.57.0 --- go.mod | 5 +++-- go.sum | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 83e4032ea..fff95b30e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spf13/afero v1.9.5 golang.org/x/sync v0.3.0 golang.org/x/sys v0.10.0 - google.golang.org/grpc v1.56.2 + google.golang.org/grpc v1.57.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/protobuf v1.31.0 k8s.io/api v0.27.3 @@ -38,6 +38,8 @@ require ( sigs.k8s.io/yaml v1.3.0 ) +require google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + require ( cloud.google.com/go/compute v1.19.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect @@ -173,7 +175,6 @@ require ( golang.org/x/tools v0.11.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index e420beab8..d138b18ef 100644 --- a/go.sum +++ b/go.sum @@ -869,8 +869,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -890,8 +890,8 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= From 46fe0dbe5ac1d0d820cc588dbbe5dcb51aa99303 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Thu, 27 Jul 2023 12:08:21 +0100 Subject: [PATCH 118/148] Add Crossplane 2023 security audit report Signed-off-by: AdamKorcz --- SECURITY.md | 3 +++ security/ADA-security-audit-23.pdf | Bin 0 -> 789756 bytes 2 files changed, 3 insertions(+) create mode 100644 security/ADA-security-audit-23.pdf diff --git a/SECURITY.md b/SECURITY.md index 471b30823..3265e9322 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,6 +11,9 @@ The following security related audits have been performed in the Crossplane project and are available for download from the [security folder](./security) and from the direct links below: +* A security audit was completed in July 2023 by [Ada + Logics](https://adalogics.com/). The full report is available + [here](./security/ADA-security-audit-23.pdf). * A fuzzing security audit was completed in March 2023 by [Ada Logics](https://adalogics.com/). The full report is available [here](./security/ADA-fuzzing-audit-22.pdf). diff --git a/security/ADA-security-audit-23.pdf b/security/ADA-security-audit-23.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b9e0f1c38c31d02b6fd8079d3f519a428b0e5805 GIT binary patch literal 789756 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∋xln=$4p_{KlvmA2z|iz^?kdiZ}K(T;gn0&0Kl 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�Z6G86bqpsQYs0tm!Ras6=&gD!t@zC4+1qB$G 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 z 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

%5pW8%Z+-BNMfgQB34=rh3A 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

B791Sf6SYRkRsLFtPJPQh(f8OPVj6``% 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Ħe-jGN!`T*DdjiJ&&jkFa-+;kW6=UT}0>_Nk%qV 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 z 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 literal 0 HcmV?d00001 From a89cf4dc89cae98f1d959bfca5d6d68f5db6fa3d Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 27 Jul 2023 16:17:40 +0200 Subject: [PATCH 119/148] ci: add cleanup disk step before publish Signed-off-by: Philippe Scorsolini --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7322164ed..1b82fb3a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,6 +305,16 @@ jobs: if: needs.detect-noop.outputs.noop != 'true' steps: + - name: Cleanup Disk + uses: jlumbroso/free-disk-space@main + with: + android: true + dotnet: true + haskell: true + tool-cache: true + large-packages: false + swap-storage: false + - name: Setup QEMU uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2 with: From 1a8a15f6f7765125213591021f073a733e1be4e0 Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Thu, 27 Jul 2023 18:34:41 +0300 Subject: [PATCH 120/148] Update release table and base branches for v1.13 Signed-off-by: ezgidemirel --- .github/renovate.json5 | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 502c999a7..0025c9c95 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -11,7 +11,7 @@ "prConcurrentLimit": 5, // The branches renovate should target // PLEASE UPDATE THIS WHEN RELEASING. - "baseBranches": ["master","release-1.10","release-1.11","release-1.12"], + "baseBranches": ["master","release-1.11","release-1.12","release-1.13"], "ignorePaths": ["design/**"], "postUpdateOptions": ["gomodTidy"], // By default renovate will auto detect whether semantic commits have been used diff --git a/README.md b/README.md index 013077ef4..8c78a064e 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ documentation]. | Release | Release Date | EOL | |:-------:|:------------:|:--------:| -| v1.10 | Oct 18, 2022 | Jul 2023 | | v1.11 | Jan 31, 2023 | Oct 2023 | | v1.12 | Apr 25, 2023 | Jan 2024 | -| v1.13 | Late Jul '23 | Apr 2024 | +| v1.13 | Jul 27, 2023 | Apr 2024 | | v1.14 | Late Oct '23 | Jul 2024 | | v1.15 | Late Jan '24 | Oct 2024 | +| v1.16 | Late Apr '24 | Jan 2025 | You can subscribe to the [community calendar] to track all release dates, and find the most recent releases on the [releases] page. From 3c13deeb80e5196ef3ca397f418fd7985b1a8f27 Mon Sep 17 00:00:00 2001 From: lsviben Date: Fri, 28 Jul 2023 13:44:35 +0200 Subject: [PATCH 121/148] injected noop logger by default to ctrl-runtime Signed-off-by: lsviben --- cmd/crossplane/main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/crossplane/main.go b/cmd/crossplane/main.go index 3c6b05153..6eab7c47f 100644 --- a/cmd/crossplane/main.go +++ b/cmd/crossplane/main.go @@ -19,6 +19,7 @@ package main import ( "fmt" + "io" "github.com/alecthomas/kong" admv1 "k8s.io/api/admissionregistration/v1" @@ -78,7 +79,11 @@ func (v versionFlag) BeforeApply(app *kong.Kong) error { //nolint:unparam // Bef func main() { zl := zap.New().WithName("crossplane") - + // Setting the controller-runtime logger to a no-op logger by default, + // unless debug mode is enabled. This is because the controller-runtime + // logger is *very* verbose even at info level. This is not really needed, + // but otherwise we get a warning from the controller-runtime. + ctrl.SetLogger(zap.New(zap.WriteTo(io.Discard))) // Note that the controller managers scheme must be a superset of the // package manager's object scheme; it must contain all object types that // may appear in a Crossplane package. This is because the package manager From d63ea37767c3272e92e9128129c27d90275c13c4 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Fri, 28 Jul 2023 15:28:03 +0200 Subject: [PATCH 122/148] intializer: update storage version of CompositionRevision CRs in etcd Signed-off-by: Philippe Scorsolini Signed-off-by: Dr. Stefan Schimanski Co-authored-by: Philippe Scorsolini --- .../crossplane/templates/clusterrole.yaml | 1 + cmd/crossplane/core/init.go | 6 +- internal/initializer/crds_migrator.go | 112 ++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 internal/initializer/crds_migrator.go diff --git a/cluster/charts/crossplane/templates/clusterrole.yaml b/cluster/charts/crossplane/templates/clusterrole.yaml index 5f0fc8af4..5559ae3ba 100644 --- a/cluster/charts/crossplane/templates/clusterrole.yaml +++ b/cluster/charts/crossplane/templates/clusterrole.yaml @@ -35,6 +35,7 @@ rules: - apiextensions.k8s.io resources: - customresourcedefinitions + - customresourcedefinitions/status verbs: - "*" - apiGroups: diff --git a/cmd/crossplane/core/init.go b/cmd/crossplane/core/init.go index 2f062c897..fcc285f58 100644 --- a/cmd/crossplane/core/init.go +++ b/cmd/crossplane/core/init.go @@ -70,10 +70,14 @@ func (c *initCommand) Run(s *runtime.Scheme, log logging.Logger) error { steps = append(steps, initializer.NewWebhookCertificateGenerator(nn, c.Namespace, log.WithValues("Step", "WebhookCertificateGenerator")), + initializer.NewCoreCRDsMigrator("compositionrevisions.apiextensions.crossplane.io", "v1alpha1"), initializer.NewCoreCRDs("/crds", s, initializer.WithWebhookTLSSecretRef(nn)), initializer.NewWebhookConfigurations("/webhookconfigurations", s, nn, svc)) } else { - steps = append(steps, initializer.NewCoreCRDs("/crds", s)) + steps = append(steps, + initializer.NewCoreCRDsMigrator("compositionrevisions.apiextensions.crossplane.io", "v1alpha1"), + initializer.NewCoreCRDs("/crds", s), + ) } if c.ESSTLSClientSecretName != "" && c.ESSTLSServerSecretName != "" { diff --git a/internal/initializer/crds_migrator.go b/internal/initializer/crds_migrator.go new file mode 100644 index 000000000..0381a5359 --- /dev/null +++ b/internal/initializer/crds_migrator.go @@ -0,0 +1,112 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package initializer + +import ( + "context" + + extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/crossplane/crossplane-runtime/pkg/errors" +) + +// NewCoreCRDsMigrator returns a new *CoreCRDsMigrator. +func NewCoreCRDsMigrator(crdName, sourceVersion string) *CoreCRDsMigrator { + c := &CoreCRDsMigrator{ + crdName: crdName, + oldVersion: sourceVersion, + } + return c +} + +// CoreCRDsMigrator makes sure the CRDs are using the latest storage version. +type CoreCRDsMigrator struct { + crdName string + oldVersion string +} + +// Run applies all CRDs in the given directory. +func (c *CoreCRDsMigrator) Run(ctx context.Context, kube client.Client) error { //nolint:gocyclo // TODO(phisco) refactor + var crd extv1.CustomResourceDefinition + if err := kube.Get(ctx, client.ObjectKey{Name: c.crdName}, &crd); err != nil { + if kerrors.IsNotFound(err) { + // nothing to do + return nil + } + return errors.Wrapf(err, "cannot get %s crd", c.crdName) + } + // no old version in the crd, nothing to do + if !sets.NewString(crd.Status.StoredVersions...).Has(c.oldVersion) { + return nil + } + // we need to patch all resources to the new storage version + var storageVersion string + for _, v := range crd.Spec.Versions { + if v.Storage { + storageVersion = v.Name + break + } + } + var resources = unstructured.UnstructuredList{} + resources.SetGroupVersionKind(schema.GroupVersionKind{ + Group: crd.Spec.Group, + Version: storageVersion, + Kind: crd.Spec.Names.ListKind, + }) + var continueToken string + for { + if err := kube.List(ctx, &resources, + client.Limit(500), + client.Continue(continueToken), + ); err != nil { + return errors.Wrapf(err, "cannot list %s", resources.GroupVersionKind().String()) + } + for i := range resources.Items { + // apply empty patch for storage version upgrade + res := resources.Items[i] + if err := kube.Patch(ctx, &res, client.RawPatch(types.MergePatchType, []byte(`{}`))); err != nil { + return errors.Wrapf(err, "cannot patch %s %q", crd.Spec.Names.Kind, res.GetName()) + } + } + continueToken = resources.GetContinue() + if continueToken == "" { + break + } + } + + origCrd := crd.DeepCopy() + crd.Status.StoredVersions = []string{storageVersion} + if err := kube.Status().Patch(ctx, &crd, client.MergeFrom(origCrd)); err != nil { + return errors.Wrapf(err, "couldn't update %s crd", c.crdName) + } + + // One more check just to be sure we actually updated the crd + if err := kube.Get(ctx, client.ObjectKey{Name: c.crdName}, &crd); err != nil { + return errors.Wrapf(err, "cannot get %s crd to check", c.crdName) + } + if !sets.NewString(crd.Status.StoredVersions...).Has(storageVersion) { + return errors.Errorf("couldn't update %s crd", c.crdName) + } + + return nil +} From 9cf338c53ae5cdc2b8858ef3e0691f277c4ea928 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Fri, 28 Jul 2023 16:37:34 +0200 Subject: [PATCH 123/148] fix: check that storeVersions ONLY contain the storageVersion after we updated it Signed-off-by: Philippe Scorsolini --- internal/initializer/crds_migrator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/initializer/crds_migrator.go b/internal/initializer/crds_migrator.go index 0381a5359..0a7987dc8 100644 --- a/internal/initializer/crds_migrator.go +++ b/internal/initializer/crds_migrator.go @@ -104,8 +104,8 @@ func (c *CoreCRDsMigrator) Run(ctx context.Context, kube client.Client) error { if err := kube.Get(ctx, client.ObjectKey{Name: c.crdName}, &crd); err != nil { return errors.Wrapf(err, "cannot get %s crd to check", c.crdName) } - if !sets.NewString(crd.Status.StoredVersions...).Has(storageVersion) { - return errors.Errorf("couldn't update %s crd", c.crdName) + if len(crd.Status.StoredVersions) != 1 || crd.Status.StoredVersions[0] != storageVersion { + return errors.Errorf("was expecting CRD %q to only have %s, got instead: %v", c.crdName, storageVersion, crd.Status.StoredVersions) } return nil From d8f77a904b56680dc14635e9d898bfdef8e7beb0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Jul 2023 14:41:15 +0000 Subject: [PATCH 124/148] Update github/codeql-action digest to 0ba4244 --- .github/workflows/ci.yml | 4 ++-- .github/workflows/scan.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b82fb3a3..89dd50844 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,12 @@ jobs: run: make vendor vendor.check - name: Initialize CodeQL - uses: github/codeql-action/init@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2 + uses: github/codeql-action/init@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2 + uses: github/codeql-action/analyze@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2 trivy-scan-fs: runs-on: ubuntu-22.04 diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml index bfcaf4b30..e1f8d0ede 100644 --- a/.github/workflows/scan.yaml +++ b/.github/workflows/scan.yaml @@ -131,7 +131,7 @@ jobs: retention-days: 3 - name: Upload Trivy Scan Results To GitHub Security Tab - uses: github/codeql-action/upload-sarif@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2 + uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 # v2 with: sarif_file: 'trivy-results.sarif' category: ${{ matrix.image }}:${{ env.tag }} From 9f5384a7e95c6fe746ef42e0b9ead4ff22bafbca Mon Sep 17 00:00:00 2001 From: Matt Bush Date: Wed, 26 Jul 2023 13:20:07 -0700 Subject: [PATCH 125/148] Add test for empty XRD Signed-off-by: Matt Bush --- internal/xcrd/crd_test.go | 710 ++++++++++++++++++++++++++++++++++---- 1 file changed, 639 insertions(+), 71 deletions(-) diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index 2cea4757d..9f3ef7ed5 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -409,6 +409,296 @@ func TestForCompositeResource(t *testing.T) { } } +func TestForCompositeResourceEmptyXrd(t *testing.T) { + name := "coolcomposites.example.org" + labels := map[string]string{"cool": "very"} + annotations := map[string]string{"example.org/cool": "very"} + + group := "example.org" + version := "v1" + kind := "CoolComposite" + listKind := "CoolCompositeList" + singular := "coolcomposite" + plural := "coolcomposites" + + schema := "{}" + + d := &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labels, + Annotations: annotations, + UID: types.UID("you-you-eye-dee"), + }, + Spec: v1.CompositeResourceDefinitionSpec{ + Group: group, + Names: extv1.CustomResourceDefinitionNames{ + Plural: plural, + Singular: singular, + Kind: kind, + ListKind: listKind, + }, + Versions: []v1.CompositeResourceDefinitionVersion{{ + Name: version, + Referenceable: true, + Served: true, + Schema: &v1.CompositeResourceValidation{ + OpenAPIV3Schema: runtime.RawExtension{Raw: []byte(schema)}, + }, + }}, + }, + } + + want := &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labels, + OwnerReferences: []metav1.OwnerReference{ + meta.AsController(meta.TypedReferenceTo(d, v1.CompositeResourceDefinitionGroupVersionKind)), + }, + }, + Spec: extv1.CustomResourceDefinitionSpec{ + Group: group, + Names: extv1.CustomResourceDefinitionNames{ + Plural: plural, + Singular: singular, + Kind: kind, + ListKind: listKind, + Categories: []string{CategoryComposite}, + }, + Scope: extv1.ClusterScoped, + Versions: []extv1.CustomResourceDefinitionVersion{{ + Name: version, + Served: true, + Storage: true, + Subresources: &extv1.CustomResourceSubresources{ + Status: &extv1.CustomResourceSubresourceStatus{}, + }, + AdditionalPrinterColumns: []extv1.CustomResourceColumnDefinition{ + { + Name: "SYNCED", + Type: "string", + JSONPath: ".status.conditions[?(@.type=='Synced')].status", + }, + { + Name: "READY", + Type: "string", + JSONPath: ".status.conditions[?(@.type=='Ready')].status", + }, + { + Name: "COMPOSITION", + Type: "string", + JSONPath: ".spec.compositionRef.name", + }, + { + Name: "AGE", + Type: "date", + JSONPath: ".metadata.creationTimestamp", + }, + }, + Schema: &extv1.CustomResourceValidation{ + OpenAPIV3Schema: &extv1.JSONSchemaProps{ + Type: "object", + Description: "", + Required: []string{"spec"}, + Properties: map[string]extv1.JSONSchemaProps{ + "apiVersion": { + Type: "string", + }, + "kind": { + Type: "string", + }, + "metadata": { + // NOTE(muvaf): api-server takes care of validating + // metadata. + Type: "object", + }, + "spec": { + Type: "object", + Description: "", + Properties: map[string]extv1.JSONSchemaProps{ + // From CompositeResourceSpecProps() + "compositionRef": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + }, + }, + "compositionSelector": { + Type: "object", + Required: []string{"matchLabels"}, + Properties: map[string]extv1.JSONSchemaProps{ + "matchLabels": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + }, + }, + "compositionRevisionRef": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + }, + }, + "compositionRevisionSelector": { + Type: "object", + Required: []string{"matchLabels"}, + Properties: map[string]extv1.JSONSchemaProps{ + "matchLabels": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + }, + }, + "compositionUpdatePolicy": { + Type: "string", + Enum: []extv1.JSON{ + {Raw: []byte(`"Automatic"`)}, + {Raw: []byte(`"Manual"`)}, + }, + }, + "claimRef": { + Type: "object", + Required: []string{"apiVersion", "kind", "namespace", "name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "apiVersion": {Type: "string"}, + "kind": {Type: "string"}, + "namespace": {Type: "string"}, + "name": {Type: "string"}, + }, + }, + "environmentConfigRefs": { + Type: "array", + Items: &extv1.JSONSchemaPropsOrArray{ + Schema: &extv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]extv1.JSONSchemaProps{ + "apiVersion": {Type: "string"}, + "name": {Type: "string"}, + "kind": {Type: "string"}, + }, + Required: []string{"apiVersion", "kind"}, + }, + }, + }, + "resourceRefs": { + Type: "array", + Items: &extv1.JSONSchemaPropsOrArray{ + Schema: &extv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]extv1.JSONSchemaProps{ + "apiVersion": {Type: "string"}, + "name": {Type: "string"}, + "kind": {Type: "string"}, + }, + Required: []string{"apiVersion", "kind"}, + }, + }, + }, + "publishConnectionDetailsTo": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + "configRef": { + Type: "object", + Default: &extv1.JSON{Raw: []byte(`{"name": "default"}`)}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": { + Type: "string", + }, + }, + }, + "metadata": { + Type: "object", + Properties: map[string]extv1.JSONSchemaProps{ + "labels": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + "annotations": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + "type": { + Type: "string", + }, + }, + }, + }, + }, + "writeConnectionSecretToRef": { + Type: "object", + Required: []string{"name", "namespace"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + "namespace": {Type: "string"}, + }, + }, + }, + }, + "status": { + Type: "object", + Description: "", + Properties: map[string]extv1.JSONSchemaProps{ + + // From CompositeResourceStatusProps() + "conditions": { + Description: "Conditions of the resource.", + Type: "array", + Items: &extv1.JSONSchemaPropsOrArray{ + Schema: &extv1.JSONSchemaProps{ + Type: "object", + Required: []string{"lastTransitionTime", "reason", "status", "type"}, + Properties: map[string]extv1.JSONSchemaProps{ + "lastTransitionTime": {Type: "string", Format: "date-time"}, + "message": {Type: "string"}, + "reason": {Type: "string"}, + "status": {Type: "string"}, + "type": {Type: "string"}, + }, + }, + }, + }, + "connectionDetails": { + Type: "object", + Properties: map[string]extv1.JSONSchemaProps{ + "lastPublishedTime": {Type: "string", Format: "date-time"}, + }, + }, + }, + }, + }, + }, + }, + }}, + }, + } + + got, err := ForCompositeResource(d) + if err != nil { + t.Fatalf("ForCompositeResource(...): %s", err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("ForCompositeResource(...): -want, +got:\n%s", diff) + } +} + func TestValidateClaimNames(t *testing.T) { cases := map[string]struct { d *v1.CompositeResourceDefinition @@ -484,30 +774,356 @@ func TestValidateClaimNames(t *testing.T) { Singular: "a", Plural: "a", }, - Names: extv1.CustomResourceDefinitionNames{ - Kind: "b", - ListKind: "b", - Singular: "b", - Plural: "a", - Categories: []string{CategoryClaim}, + Names: extv1.CustomResourceDefinitionNames{ + Kind: "b", + ListKind: "b", + Singular: "b", + Plural: "a", + Categories: []string{CategoryClaim}, + }, + }, + }, + want: errors.Errorf(errFmtConflictingClaimName, "a"), + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := validateClaimNames(tc.d) + if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" { + t.Errorf("validateClaimNames(...): -want, +got:\n%s", diff) + } + }) + } +} + +func TestForCompositeResourceClaim(t *testing.T) { + name := "coolcomposites.example.org" + labels := map[string]string{"cool": "very"} + annotations := map[string]string{"example.org/cool": "very"} + + group := "example.org" + version := "v1" + + kind := "CoolComposite" + listKind := "CoolCompositeList" + singular := "coolcomposite" + plural := "coolcomposites" + + claimKind := "CoolClaim" + claimListKind := "CoolClaimList" + claimSingular := "coolclaim" + claimPlural := "coolclaims" + + schema := ` +{ + "properties": { + "spec": { + "description": "Specification of the resource.", + "required": [ + "storageGB", + "engineVersion" + ], + "properties": { + "engineVersion": { + "enum": [ + "5.6", + "5.7" + ], + "type": "string" + }, + "storageGB": { + "type": "integer", + "description": "Pretend this is useful." + } + }, + "type": "object" + }, + "status": { + "properties": { + "phase": { + "type": "string" + } + }, + "type": "object", + "description": "Status of the resource." + } + }, + "type": "object", + "description": "Description of the resource." +}` + + d := &v1.CompositeResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: labels, + Annotations: annotations, + UID: types.UID("you-you-eye-dee"), + }, + Spec: v1.CompositeResourceDefinitionSpec{ + Group: group, + Names: extv1.CustomResourceDefinitionNames{ + Plural: plural, + Singular: singular, + Kind: kind, + ListKind: listKind, + }, + ClaimNames: &extv1.CustomResourceDefinitionNames{ + Plural: claimPlural, + Singular: claimSingular, + Kind: claimKind, + ListKind: claimListKind, + }, + Versions: []v1.CompositeResourceDefinitionVersion{{ + Name: version, + Referenceable: true, + Served: true, + Schema: &v1.CompositeResourceValidation{ + OpenAPIV3Schema: runtime.RawExtension{Raw: []byte(schema)}, + }, + }}, + }, + } + + want := &extv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: claimPlural + "." + group, + Labels: labels, + OwnerReferences: []metav1.OwnerReference{ + meta.AsController(meta.TypedReferenceTo(d, v1.CompositeResourceDefinitionGroupVersionKind)), + }, + }, + Spec: extv1.CustomResourceDefinitionSpec{ + Group: group, + Names: extv1.CustomResourceDefinitionNames{ + Plural: claimPlural, + Singular: claimSingular, + Kind: claimKind, + ListKind: claimListKind, + Categories: []string{CategoryClaim}, + }, + Scope: extv1.NamespaceScoped, + Versions: []extv1.CustomResourceDefinitionVersion{ + { + Name: version, + Served: true, + Storage: true, + Subresources: &extv1.CustomResourceSubresources{ + Status: &extv1.CustomResourceSubresourceStatus{}, + }, + AdditionalPrinterColumns: []extv1.CustomResourceColumnDefinition{ + { + Name: "SYNCED", + Type: "string", + JSONPath: ".status.conditions[?(@.type=='Synced')].status", + }, + { + Name: "READY", + Type: "string", + JSONPath: ".status.conditions[?(@.type=='Ready')].status", + }, + { + Name: "CONNECTION-SECRET", + Type: "string", + JSONPath: ".spec.writeConnectionSecretToRef.name", + }, + { + Name: "AGE", + Type: "date", + JSONPath: ".metadata.creationTimestamp", + }, + }, + Schema: &extv1.CustomResourceValidation{ + OpenAPIV3Schema: &extv1.JSONSchemaProps{ + Type: "object", + Required: []string{"spec"}, + Description: "Description of the resource.", + Properties: map[string]extv1.JSONSchemaProps{ + "apiVersion": { + Type: "string", + }, + "kind": { + Type: "string", + }, + "metadata": { + // NOTE(muvaf): api-server takes care of validating + // metadata. + Type: "object", + }, + "spec": { + Type: "object", + Required: []string{"storageGB", "engineVersion"}, + Description: "Specification of the resource.", + Properties: map[string]extv1.JSONSchemaProps{ + // From CRDSpecTemplate.Validation + "storageGB": {Type: "integer", Description: "Pretend this is useful."}, + "engineVersion": { + Type: "string", + Enum: []extv1.JSON{ + {Raw: []byte(`"5.6"`)}, + {Raw: []byte(`"5.7"`)}, + }, + }, + "compositeDeletePolicy": { + Type: "string", + Enum: []extv1.JSON{{Raw: []byte(`"Background"`)}, + {Raw: []byte(`"Foreground"`)}}, + }, + // From CompositeResourceClaimSpecProps() + "compositionRef": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + }, + }, + "compositionSelector": { + Type: "object", + Required: []string{"matchLabels"}, + Properties: map[string]extv1.JSONSchemaProps{ + "matchLabels": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + }, + }, + "compositionRevisionRef": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + }, + }, + "compositionRevisionSelector": { + Type: "object", + Required: []string{"matchLabels"}, + Properties: map[string]extv1.JSONSchemaProps{ + "matchLabels": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + }, + }, + "compositionUpdatePolicy": { + Type: "string", + Enum: []extv1.JSON{ + {Raw: []byte(`"Automatic"`)}, + {Raw: []byte(`"Manual"`)}, + }, + }, + "resourceRef": { + Type: "object", + Required: []string{"apiVersion", "kind", "name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "apiVersion": {Type: "string"}, + "kind": {Type: "string"}, + "name": {Type: "string"}, + }, + }, + "publishConnectionDetailsTo": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + "configRef": { + Type: "object", + Default: &extv1.JSON{Raw: []byte(`{"name": "default"}`)}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": { + Type: "string", + }, + }, + }, + "metadata": { + Type: "object", + Properties: map[string]extv1.JSONSchemaProps{ + "labels": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + "annotations": { + Type: "object", + AdditionalProperties: &extv1.JSONSchemaPropsOrBool{ + Allows: true, + Schema: &extv1.JSONSchemaProps{Type: "string"}, + }, + }, + "type": { + Type: "string", + }, + }, + }, + }, + }, + "writeConnectionSecretToRef": { + Type: "object", + Required: []string{"name"}, + Properties: map[string]extv1.JSONSchemaProps{ + "name": {Type: "string"}, + }, + }, + }, + }, + "status": { + Type: "object", + Description: "Status of the resource.", + Properties: map[string]extv1.JSONSchemaProps{ + "phase": {Type: "string"}, + + // From CompositeResourceStatusProps() + "conditions": { + Description: "Conditions of the resource.", + Type: "array", + Items: &extv1.JSONSchemaPropsOrArray{ + Schema: &extv1.JSONSchemaProps{ + Type: "object", + Required: []string{"lastTransitionTime", "reason", "status", "type"}, + Properties: map[string]extv1.JSONSchemaProps{ + "lastTransitionTime": {Type: "string", Format: "date-time"}, + "message": {Type: "string"}, + "reason": {Type: "string"}, + "status": {Type: "string"}, + "type": {Type: "string"}, + }, + }, + }, + }, + "connectionDetails": { + Type: "object", + Properties: map[string]extv1.JSONSchemaProps{ + "lastPublishedTime": {Type: "string", Format: "date-time"}, + }, + }, + }, + }, + }, + }, }, }, }, - want: errors.Errorf(errFmtConflictingClaimName, "a"), }, } - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - got := validateClaimNames(tc.d) - if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" { - t.Errorf("validateClaimNames(...): -want, +got:\n%s", diff) - } - }) + got, err := ForCompositeResourceClaim(d) + if err != nil { + t.Fatalf("ForCompositeResourceClaim(...): %s", err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("ForCompositeResourceClaim(...): -want, +got:\n%s", diff) } } -func TestForCompositeResourceClaim(t *testing.T) { +func TestForCompositeResourceClaimEmptyXrd(t *testing.T) { name := "coolcomposites.example.org" labels := map[string]string{"cool": "very"} annotations := map[string]string{"example.org/cool": "very"} @@ -525,43 +1141,7 @@ func TestForCompositeResourceClaim(t *testing.T) { claimSingular := "coolclaim" claimPlural := "coolclaims" - schema := ` -{ - "properties": { - "spec": { - "description": "Specification of the resource.", - "required": [ - "storageGB", - "engineVersion" - ], - "properties": { - "engineVersion": { - "enum": [ - "5.6", - "5.7" - ], - "type": "string" - }, - "storageGB": { - "type": "integer", - "description": "Pretend this is useful." - } - }, - "type": "object" - }, - "status": { - "properties": { - "phase": { - "type": "string" - } - }, - "type": "object", - "description": "Status of the resource." - } - }, - "type": "object", - "description": "Description of the resource." -}` + schema := "{}" d := &v1.CompositeResourceDefinition{ ObjectMeta: metav1.ObjectMeta{ @@ -645,9 +1225,9 @@ func TestForCompositeResourceClaim(t *testing.T) { }, Schema: &extv1.CustomResourceValidation{ OpenAPIV3Schema: &extv1.JSONSchemaProps{ - Type: "object", - Required: []string{"spec"}, - Description: "Description of the resource.", + Type: "object", + Required: []string{"spec"}, + Description: "", Properties: map[string]extv1.JSONSchemaProps{ "apiVersion": { Type: "string", @@ -661,19 +1241,9 @@ func TestForCompositeResourceClaim(t *testing.T) { Type: "object", }, "spec": { - Type: "object", - Required: []string{"storageGB", "engineVersion"}, - Description: "Specification of the resource.", + Type: "object", + Description: "", Properties: map[string]extv1.JSONSchemaProps{ - // From CRDSpecTemplate.Validation - "storageGB": {Type: "integer", Description: "Pretend this is useful."}, - "engineVersion": { - Type: "string", - Enum: []extv1.JSON{ - {Raw: []byte(`"5.6"`)}, - {Raw: []byte(`"5.7"`)}, - }, - }, "compositeDeletePolicy": { Type: "string", Enum: []extv1.JSON{{Raw: []byte(`"Background"`)}, @@ -784,11 +1354,9 @@ func TestForCompositeResourceClaim(t *testing.T) { }, }, "status": { - Type: "object", - Description: "Status of the resource.", + Type: "object", + Description: "", Properties: map[string]extv1.JSONSchemaProps{ - "phase": {Type: "string"}, - // From CompositeResourceStatusProps() "conditions": { Description: "Conditions of the resource.", From 4344780f29477ffea921d32e4ecad6bab925d861 Mon Sep 17 00:00:00 2001 From: Matt Bush Date: Mon, 24 Jul 2023 16:00:08 -0700 Subject: [PATCH 126/148] fix: Pass description fields in XRDs into CRDs Signed-off-by: Matt Bush --- internal/xcrd/crd.go | 147 ++++++++++++++++---------------------- internal/xcrd/crd_test.go | 94 ++++++++++++------------ 2 files changed, 107 insertions(+), 134 deletions(-) diff --git a/internal/xcrd/crd.go b/internal/xcrd/crd.go index cb3e046fd..9749f2768 100644 --- a/internal/xcrd/crd.go +++ b/internal/xcrd/crd.go @@ -42,7 +42,7 @@ const ( ) const ( - errFmtGetProps = "cannot get %q properties from validation schema" + errFmtGenCrd = "cannot generate CRD for %q %q" errParseValidation = "cannot parse validation schema" errInvalidClaimNames = "invalid resource claim names" errMissingClaimNames = "missing names" @@ -71,48 +71,15 @@ func ForCompositeResource(xrd *v1.CompositeResourceDefinition) (*extv1.CustomRes crd.Spec.Names.Categories = append(crd.Spec.Names.Categories, CategoryComposite) for i, vr := range xrd.Spec.Versions { - crd.Spec.Versions[i] = extv1.CustomResourceDefinitionVersion{ - Name: vr.Name, - Served: vr.Served, - Storage: vr.Referenceable, - Deprecated: pointer.BoolDeref(vr.Deprecated, false), - DeprecationWarning: vr.DeprecationWarning, - AdditionalPrinterColumns: append(vr.AdditionalPrinterColumns, CompositeResourcePrinterColumns()...), - Schema: &extv1.CustomResourceValidation{ - OpenAPIV3Schema: BaseProps(), - }, - Subresources: &extv1.CustomResourceSubresources{ - Status: &extv1.CustomResourceSubresourceStatus{}, - }, - } - - p, required, err := getProps("spec", vr.Schema) + crdv, err := genCrdVersion(vr) if err != nil { - return nil, errors.Wrapf(err, errFmtGetProps, "spec") - } - specProps := crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["spec"] - specProps.Required = append(specProps.Required, required...) - for k, v := range p { - specProps.Properties[k] = v + return nil, errors.Wrapf(err, errFmtGenCrd, "Composite Resource", xrd.Name) } + crdv.AdditionalPrinterColumns = append(crdv.AdditionalPrinterColumns, CompositeResourcePrinterColumns()...) for k, v := range CompositeResourceSpecProps() { - specProps.Properties[k] = v - } - crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["spec"] = specProps - - statusP, statusRequired, err := getProps("status", vr.Schema) - if err != nil { - return nil, errors.Wrapf(err, errFmtGetProps, "status") - } - statusProps := crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["status"] - statusProps.Required = statusRequired - for k, v := range statusP { - statusProps.Properties[k] = v - } - for k, v := range CompositeResourceStatusProps() { - statusProps.Properties[k] = v + crdv.Schema.OpenAPIV3Schema.Properties["spec"].Properties[k] = v } - crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["status"] = statusProps + crd.Spec.Versions[i] = *crdv } return crd, nil @@ -144,53 +111,65 @@ func ForCompositeResourceClaim(xrd *v1.CompositeResourceDefinition) (*extv1.Cust crd.Spec.Names.Categories = append(crd.Spec.Names.Categories, CategoryClaim) for i, vr := range xrd.Spec.Versions { - crd.Spec.Versions[i] = extv1.CustomResourceDefinitionVersion{ - Name: vr.Name, - Served: vr.Served, - Storage: vr.Referenceable, - Deprecated: pointer.BoolDeref(vr.Deprecated, false), - DeprecationWarning: vr.DeprecationWarning, - AdditionalPrinterColumns: append(vr.AdditionalPrinterColumns, CompositeResourceClaimPrinterColumns()...), - Schema: &extv1.CustomResourceValidation{ - OpenAPIV3Schema: BaseProps(), - }, - Subresources: &extv1.CustomResourceSubresources{ - Status: &extv1.CustomResourceSubresourceStatus{}, - }, - } - - p, required, err := getProps("spec", vr.Schema) + crdv, err := genCrdVersion(vr) if err != nil { - return nil, errors.Wrapf(err, errFmtGetProps, "spec") - } - specProps := crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["spec"] - specProps.Required = append(specProps.Required, required...) - for k, v := range p { - specProps.Properties[k] = v + return nil, errors.Wrapf(err, errFmtGenCrd, "Composite Resource Claim", xrd.Name) } + crdv.AdditionalPrinterColumns = append(crdv.AdditionalPrinterColumns, CompositeResourceClaimPrinterColumns()...) for k, v := range CompositeResourceClaimSpecProps() { - specProps.Properties[k] = v - } - crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["spec"] = specProps - - statusP, statusRequired, err := getProps("status", vr.Schema) - if err != nil { - return nil, errors.Wrapf(err, errFmtGetProps, "status") - } - statusProps := crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["status"] - statusProps.Required = statusRequired - for k, v := range statusP { - statusProps.Properties[k] = v + crdv.Schema.OpenAPIV3Schema.Properties["spec"].Properties[k] = v } - for k, v := range CompositeResourceStatusProps() { - statusProps.Properties[k] = v - } - crd.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["status"] = statusProps + crd.Spec.Versions[i] = *crdv } return crd, nil } +func genCrdVersion(vr v1.CompositeResourceDefinitionVersion) (*extv1.CustomResourceDefinitionVersion, error) { + crdv := extv1.CustomResourceDefinitionVersion{ + Name: vr.Name, + Served: vr.Served, + Storage: vr.Referenceable, + Deprecated: pointer.BoolDeref(vr.Deprecated, false), + DeprecationWarning: vr.DeprecationWarning, + AdditionalPrinterColumns: vr.AdditionalPrinterColumns, + Schema: &extv1.CustomResourceValidation{ + OpenAPIV3Schema: BaseProps(), + }, + Subresources: &extv1.CustomResourceSubresources{ + Status: &extv1.CustomResourceSubresourceStatus{}, + }, + } + s, err := parseSchema(vr.Schema) + if err != nil { + return nil, errors.Wrapf(err, errParseValidation) + } + crdv.Schema.OpenAPIV3Schema.Description = s.Description + + xSpec := s.Properties["spec"] + cSpec := crdv.Schema.OpenAPIV3Schema.Properties["spec"] + cSpec.Required = append(cSpec.Required, xSpec.Required...) + + cSpec.Description = xSpec.Description + for k, v := range xSpec.Properties { + cSpec.Properties[k] = v + } + crdv.Schema.OpenAPIV3Schema.Properties["spec"] = cSpec + + xStatus := s.Properties["status"] + cStatus := crdv.Schema.OpenAPIV3Schema.Properties["status"] + cStatus.Required = xStatus.Required + cStatus.Description = xStatus.Description + for k, v := range xStatus.Properties { + cStatus.Properties[k] = v + } + for k, v := range CompositeResourceStatusProps() { + cStatus.Properties[k] = v + } + crdv.Schema.OpenAPIV3Schema.Properties["status"] = cStatus + return &crdv, nil +} + func validateClaimNames(d *v1.CompositeResourceDefinition) error { if d.Spec.ClaimNames == nil { return errors.New(errMissingClaimNames) @@ -215,22 +194,16 @@ func validateClaimNames(d *v1.CompositeResourceDefinition) error { return nil } -func getProps(field string, v *v1.CompositeResourceValidation) (map[string]extv1.JSONSchemaProps, []string, error) { +func parseSchema(v *v1.CompositeResourceValidation) (*extv1.JSONSchemaProps, error) { if v == nil { - return nil, nil, nil + return nil, nil } s := &extv1.JSONSchemaProps{} if err := json.Unmarshal(v.OpenAPIV3Schema.Raw, s); err != nil { - return nil, nil, errors.Wrap(err, errParseValidation) + return nil, errors.Wrap(err, errParseValidation) } - - spec, ok := s.Properties[field] - if !ok { - return nil, nil, nil - } - - return spec.Properties, spec.Required, nil + return s, nil } // setCrdMetadata sets the labels and annotations on the CRD. diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index 9f3ef7ed5..fdc4e06ad 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -82,43 +82,43 @@ func TestForCompositeResource(t *testing.T) { schema := ` { - "required": [ - "spec" - ], - "properties": { - "spec": { - "description": "Specification of the resource.", - "required": [ - "storageGB", - "engineVersion" - ], - "properties": { - "engineVersion": { - "enum": [ - "5.6", - "5.7" - ], - "type": "string" - }, - "storageGB": { - "type": "integer", - "description": "Pretend this is useful." - } - }, - "type": "object" - }, - "status": { - "properties": { - "phase": { - "type": "string" - } - }, - "type": "object", - "description": "Status of the resource." - } - }, - "type": "object", - "description": "What the resource is for." + "required": [ + "spec" + ], + "properties": { + "spec": { + "description": "Specification of the resource.", + "required": [ + "storageGB", + "engineVersion" + ], + "properties": { + "engineVersion": { + "enum": [ + "5.6", + "5.7" + ], + "type": "string" + }, + "storageGB": { + "type": "integer", + "description": "Pretend this is useful." + } + }, + "type": "object" + }, + "status": { + "properties": { + "phase": { + "type": "string" + } + }, + "type": "object", + "description": "Status of the resource." + } + }, + "type": "object", + "description": "What the resource is for." }` d := &v1.CompositeResourceDefinition{ @@ -196,9 +196,9 @@ func TestForCompositeResource(t *testing.T) { }, Schema: &extv1.CustomResourceValidation{ OpenAPIV3Schema: &extv1.JSONSchemaProps{ - Type: "object", + Type: "object", Description: "What the resource is for.", - Required: []string{"spec"}, + Required: []string{"spec"}, Properties: map[string]extv1.JSONSchemaProps{ "apiVersion": { Type: "string", @@ -212,8 +212,8 @@ func TestForCompositeResource(t *testing.T) { Type: "object", }, "spec": { - Type: "object", - Required: []string{"storageGB", "engineVersion"}, + Type: "object", + Required: []string{"storageGB", "engineVersion"}, Description: "Specification of the resource.", Properties: map[string]extv1.JSONSchemaProps{ // From CRDSpecTemplate.Validation @@ -361,7 +361,7 @@ func TestForCompositeResource(t *testing.T) { }, }, "status": { - Type: "object", + Type: "object", Description: "Status of the resource.", Properties: map[string]extv1.JSONSchemaProps{ "phase": {Type: "string"}, @@ -935,8 +935,8 @@ func TestForCompositeResourceClaim(t *testing.T) { }, Schema: &extv1.CustomResourceValidation{ OpenAPIV3Schema: &extv1.JSONSchemaProps{ - Type: "object", - Required: []string{"spec"}, + Type: "object", + Required: []string{"spec"}, Description: "Description of the resource.", Properties: map[string]extv1.JSONSchemaProps{ "apiVersion": { @@ -951,8 +951,8 @@ func TestForCompositeResourceClaim(t *testing.T) { Type: "object", }, "spec": { - Type: "object", - Required: []string{"storageGB", "engineVersion"}, + Type: "object", + Required: []string{"storageGB", "engineVersion"}, Description: "Specification of the resource.", Properties: map[string]extv1.JSONSchemaProps{ // From CRDSpecTemplate.Validation @@ -1074,7 +1074,7 @@ func TestForCompositeResourceClaim(t *testing.T) { }, }, "status": { - Type: "object", + Type: "object", Description: "Status of the resource.", Properties: map[string]extv1.JSONSchemaProps{ "phase": {Type: "string"}, From 8d17fae57015de12518b2af04e20843ab68f432a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 31 Jul 2023 01:43:03 +0000 Subject: [PATCH 127/148] Update mikefarah/yq Docker tag to v4.34.2 --- test/e2e/testdata/images/tmp-writer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/testdata/images/tmp-writer/Dockerfile b/test/e2e/testdata/images/tmp-writer/Dockerfile index 2c3a47fec..c5dc38d5e 100644 --- a/test/e2e/testdata/images/tmp-writer/Dockerfile +++ b/test/e2e/testdata/images/tmp-writer/Dockerfile @@ -1,4 +1,4 @@ -FROM mikefarah/yq:4.34.1 +FROM mikefarah/yq:4.34.2 COPY --chmod=+x writer.sh /bin USER root From 11e7740557f203df251eb462a197007b286ca545 Mon Sep 17 00:00:00 2001 From: Predrag Knezevic Date: Mon, 31 Jul 2023 16:21:14 +0200 Subject: [PATCH 128/148] Add Predrag as reviewer Signed-off-by: Predrag Knezevic --- OWNERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS.md b/OWNERS.md index 872c7e286..7a98796ad 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -40,6 +40,7 @@ See [CODEOWNERS](CODEOWNERS) for automatic PR assignment. * Max Blatt ([MisterMX](https://github.com/MisterMX)) * Jared Watts ([jbw976](https://github.com/jbw976)) * Lovro Sviben ([lsviben](https://github.com/lsviben)) +* Predrag Knezevic ([pedjak](https://github.com/pedjak)) ## Emeritus maintainers From 0ea88b64d1f31d917fd718a9afc1615c6d2efad7 Mon Sep 17 00:00:00 2001 From: Amund Tenstad Date: Tue, 1 Aug 2023 10:07:59 +0200 Subject: [PATCH 129/148] feat: copy x-kubernetes-validations from spec to composite/claim CRDs Signed-off-by: Amund Tenstad --- internal/xcrd/crd.go | 1 + internal/xcrd/crd_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/internal/xcrd/crd.go b/internal/xcrd/crd.go index 9749f2768..aba49fdf1 100644 --- a/internal/xcrd/crd.go +++ b/internal/xcrd/crd.go @@ -149,6 +149,7 @@ func genCrdVersion(vr v1.CompositeResourceDefinitionVersion) (*extv1.CustomResou xSpec := s.Properties["spec"] cSpec := crdv.Schema.OpenAPIV3Schema.Properties["spec"] cSpec.Required = append(cSpec.Required, xSpec.Required...) + cSpec.XValidations = append(cSpec.XValidations, xSpec.XValidations...) cSpec.Description = xSpec.Description for k, v := range xSpec.Properties { diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index fdc4e06ad..ca9f99859 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -105,6 +105,12 @@ func TestForCompositeResource(t *testing.T) { "description": "Pretend this is useful." } }, + "x-kubernetes-validations": [ + { + "message": "Cannot remove engineVersion", + "rule": "!has(oldSelf.engineVersion) || has(self.engineVersion)" + } + ], "type": "object" }, "status": { @@ -359,6 +365,12 @@ func TestForCompositeResource(t *testing.T) { }, }, }, + XValidations: extv1.ValidationRules{ + { + Message: "Cannot remove engineVersion", + Rule: "!has(oldSelf.engineVersion) || has(self.engineVersion)", + }, + }, }, "status": { Type: "object", @@ -837,6 +849,12 @@ func TestForCompositeResourceClaim(t *testing.T) { "description": "Pretend this is useful." } }, + "x-kubernetes-validations": [ + { + "message": "Cannot remove engineVersion", + "rule": "!has(oldSelf.engineVersion) || has(self.engineVersion)" + } + ], "type": "object" }, "status": { @@ -1072,6 +1090,12 @@ func TestForCompositeResourceClaim(t *testing.T) { }, }, }, + XValidations: extv1.ValidationRules{ + { + Message: "Cannot remove engineVersion", + Rule: "!has(oldSelf.engineVersion) || has(self.engineVersion)", + }, + }, }, "status": { Type: "object", From fbcce5b0a220e791e2c03057dc54606d38005c17 Mon Sep 17 00:00:00 2001 From: Amund Tenstad Date: Tue, 1 Aug 2023 13:30:42 +0200 Subject: [PATCH 130/148] fix: improve validation example in test Signed-off-by: Amund Tenstad --- internal/xcrd/crd_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index ca9f99859..3bc378d25 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -107,8 +107,8 @@ func TestForCompositeResource(t *testing.T) { }, "x-kubernetes-validations": [ { - "message": "Cannot remove engineVersion", - "rule": "!has(oldSelf.engineVersion) || has(self.engineVersion)" + "message": "Cannot change engine version", + "rule": "self.engineVersion == oldSelf.engineVersion" } ], "type": "object" @@ -367,8 +367,8 @@ func TestForCompositeResource(t *testing.T) { }, XValidations: extv1.ValidationRules{ { - Message: "Cannot remove engineVersion", - Rule: "!has(oldSelf.engineVersion) || has(self.engineVersion)", + Message: "Cannot change engine version", + Rule: "self.engineVersion == oldSelf.engineVersion", }, }, }, @@ -851,8 +851,8 @@ func TestForCompositeResourceClaim(t *testing.T) { }, "x-kubernetes-validations": [ { - "message": "Cannot remove engineVersion", - "rule": "!has(oldSelf.engineVersion) || has(self.engineVersion)" + "message": "Cannot change engine version", + "rule": "self.engineVersion == oldSelf.engineVersion" } ], "type": "object" @@ -1092,8 +1092,8 @@ func TestForCompositeResourceClaim(t *testing.T) { }, XValidations: extv1.ValidationRules{ { - Message: "Cannot remove engineVersion", - Rule: "!has(oldSelf.engineVersion) || has(self.engineVersion)", + Message: "Cannot change engine version", + Rule: "self.engineVersion == oldSelf.engineVersion", }, }, }, From 396d658555d19c26c41f09525d11a6e6c512344e Mon Sep 17 00:00:00 2001 From: Amund Tenstad Date: Tue, 1 Aug 2023 13:39:14 +0200 Subject: [PATCH 131/148] feat: copy x-kubernetes-validations from status to composite/claim CRDs Signed-off-by: Amund Tenstad --- internal/xcrd/crd.go | 1 + internal/xcrd/crd_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/internal/xcrd/crd.go b/internal/xcrd/crd.go index aba49fdf1..c8f65e0a4 100644 --- a/internal/xcrd/crd.go +++ b/internal/xcrd/crd.go @@ -160,6 +160,7 @@ func genCrdVersion(vr v1.CompositeResourceDefinitionVersion) (*extv1.CustomResou xStatus := s.Properties["status"] cStatus := crdv.Schema.OpenAPIV3Schema.Properties["status"] cStatus.Required = xStatus.Required + cStatus.XValidations = xStatus.XValidations cStatus.Description = xStatus.Description for k, v := range xStatus.Properties { cStatus.Properties[k] = v diff --git a/internal/xcrd/crd_test.go b/internal/xcrd/crd_test.go index 3bc378d25..3fec78d33 100644 --- a/internal/xcrd/crd_test.go +++ b/internal/xcrd/crd_test.go @@ -119,6 +119,12 @@ func TestForCompositeResource(t *testing.T) { "type": "string" } }, + "x-kubernetes-validations": [ + { + "message": "Phase is required once set", + "rule": "!has(oldSelf.phase) || has(self.phase)" + } + ], "type": "object", "description": "Status of the resource." } @@ -403,6 +409,12 @@ func TestForCompositeResource(t *testing.T) { }, }, }, + XValidations: extv1.ValidationRules{ + { + Message: "Phase is required once set", + Rule: "!has(oldSelf.phase) || has(self.phase)", + }, + }, }, }, }, @@ -863,6 +875,12 @@ func TestForCompositeResourceClaim(t *testing.T) { "type": "string" } }, + "x-kubernetes-validations": [ + { + "message": "Phase is required once set", + "rule": "!has(oldSelf.phase) || has(self.phase)" + } + ], "type": "object", "description": "Status of the resource." } @@ -1128,6 +1146,12 @@ func TestForCompositeResourceClaim(t *testing.T) { }, }, }, + XValidations: extv1.ValidationRules{ + { + Message: "Phase is required once set", + Rule: "!has(oldSelf.phase) || has(self.phase)", + }, + }, }, }, }, From 7a9b80d9782c1da0990af0d43895d93fd4db20bc Mon Sep 17 00:00:00 2001 From: lsviben Date: Mon, 31 Jul 2023 15:48:35 +0200 Subject: [PATCH 132/148] Update the status of observe-only and ignore-changes design docs Signed-off-by: lsviben --- design/design-doc-observe-only-resources.md | 7 ++++++- design/one-pager-ignore-changes.md | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/design/design-doc-observe-only-resources.md b/design/design-doc-observe-only-resources.md index 01067c4c3..04ba953ec 100644 --- a/design/design-doc-observe-only-resources.md +++ b/design/design-doc-observe-only-resources.md @@ -2,7 +2,7 @@ * Owners: Hasan Turken (@turkenh) * Reviewers: Crossplane Maintainers -* Status: Draft +* Status: Accepted ## Background @@ -82,6 +82,10 @@ the desired state and the observed state of the resource and when the updated with the latest observation of the resource. ### Management Policy +> [!NOTE] +> The management policy was significantly changed in a +subsequent design for [ignore changes]. Keeping this section for historical +purposes. To support observing resources without taking ownership, we will introduce a new spec named `managementPolicy` to the Managed Resources. We will also deprecate @@ -713,3 +717,4 @@ it as a migration path to Crossplane. [desired tags]: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc#tags [passing sensitive configuration]: https://github.com/crossplane/crossplane/pull/2886#discussion_r862615416 [`type: Webhook` composition function]: https://github.com/crossplane/crossplane/blob/master/design/design-doc-composition-functions.md#using-webhooks-to-run-functions +[ignore changes]: https://github.com/crossplane/crossplane/blob/ad0ff7d6d0e4850168883905ed8e1509089cea15/design/one-pager-ignore-changes.md \ No newline at end of file diff --git a/design/one-pager-ignore-changes.md b/design/one-pager-ignore-changes.md index 1bfb5e81a..d0eccc0ca 100644 --- a/design/one-pager-ignore-changes.md +++ b/design/one-pager-ignore-changes.md @@ -2,7 +2,7 @@ * Owners: Lovro Sviben (@lsviben) * Reviewers: @turkenh, @negz -* Status: Draft +* Status: Accepted ## Background From 2cdc117c4bc6275f0e98e00a18ca47d317390bfd Mon Sep 17 00:00:00 2001 From: diouze Date: Tue, 1 Aug 2023 21:01:48 +0200 Subject: [PATCH 133/148] Update ADOPTERS.md Signed-off-by: diouze --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index b7de3eb1a..1fb265c87 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -52,3 +52,4 @@ This list is sorted in the order that organizations were added to it. | [NASA Science Cloud](https://smce.nasa.gov/) | [ramon.e.ramirez-linan@nasa.gov](mailto:ramon.e.ramirez-linan@nasa.gov) ([@rezuma](https://github.com/rezuma)) | [NASA Science Cloud](https://smce.nasa.gov) has created compositions to deploy the Open Science Studio, a jupyterhub based platform that connects to HPC in the cloud and foster NASA Open Science Initiative. Navteca ([@navteca](https://github.com/Navteca)) has been helping NASA with this initiative | | [Navteca](https://navteca.com/) | [rlinan@navteca.com](mailto:rlinan@navteca.com) ([@navteca](https://github.com/Navteca)) | [Navteca](https://www.navteca.com) is adopting Crossplane to deploy [Voice Atlas](https://www.voiceatlas.com) a cloud based product that let customer connect corporate knowledge with any Large Language Model and offered to be consumed by users through any channel (slack, MS Teams, Website, etc) | | [SAP](https://sap.com/) | [d.small@sap.com](mailto:d.small@sap.com)| [SAP](https://sap.com) uses Crossplane as part of a solution that gives teams owning micro-services the ability to provision hyper-scaler hosted backing services such as Redis on demand. | +| [Airnity](https://airnity.com/) | [hello@airnity.com](mailto:hello@airnity.com) | [Airnity](https://airnity.com/) uses Crossplane to deploy a worldwide cellular connectivity platform for the automotive industry. | From d03b316c5031166eba8f91a590a7777844dfd32a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 20:43:21 +0000 Subject: [PATCH 134/148] Update dependency golang to v1.20.7 --- .github/workflows/ci.yml | 2 +- .github/workflows/promote.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89dd50844..22ee86fcb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: env: # Common versions - GO_VERSION: '1.20.6' + GO_VERSION: '1.20.7' GOLANGCI_VERSION: 'v1.53.3' DOCKER_BUILDX_VERSION: 'v0.10.0' diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index b52d7c039..2c0955cfc 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -13,7 +13,7 @@ on: env: # Common versions - GO_VERSION: '1.20.6' + GO_VERSION: '1.20.7' # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether From c39785ec796b59756c99ad1c6f4485ddeb07b36d Mon Sep 17 00:00:00 2001 From: ezgidemirel Date: Wed, 2 Aug 2023 12:23:51 +0300 Subject: [PATCH 135/148] Introduce Function CRDs Signed-off-by: ezgidemirel --- apis/apiextensions/v1alpha1/register.go | 2 +- apis/pkg/v1alpha1/function_types.go | 103 +++++++ apis/pkg/v1alpha1/register.go | 8 + apis/pkg/v1alpha1/zz_generated.deepcopy.go | 151 +++++++++ .../pkg.crossplane.io_functionrevisions.yaml | 287 ++++++++++++++++++ cluster/crds/pkg.crossplane.io_functions.yaml | 171 +++++++++++ cluster/kustomization.yaml | 2 + .../typed/pkg/v1alpha1/fake/fake_function.go | 132 ++++++++ .../v1alpha1/fake/fake_functionrevision.go | 132 ++++++++ .../pkg/v1alpha1/fake/fake_pkg_client.go | 8 + .../versioned/typed/pkg/v1alpha1/function.go | 184 +++++++++++ .../typed/pkg/v1alpha1/functionrevision.go | 184 +++++++++++ .../typed/pkg/v1alpha1/generated_expansion.go | 4 + .../typed/pkg/v1alpha1/pkg_client.go | 10 + 14 files changed, 1377 insertions(+), 1 deletion(-) create mode 100644 apis/pkg/v1alpha1/function_types.go create mode 100644 cluster/crds/pkg.crossplane.io_functionrevisions.yaml create mode 100644 cluster/crds/pkg.crossplane.io_functions.yaml create mode 100644 internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_function.go create mode 100644 internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_functionrevision.go create mode 100644 internal/client/clientset/versioned/typed/pkg/v1alpha1/function.go create mode 100644 internal/client/clientset/versioned/typed/pkg/v1alpha1/functionrevision.go diff --git a/apis/apiextensions/v1alpha1/register.go b/apis/apiextensions/v1alpha1/register.go index 881865396..2e2e04e63 100644 --- a/apis/apiextensions/v1alpha1/register.go +++ b/apis/apiextensions/v1alpha1/register.go @@ -40,7 +40,7 @@ var ( AddToScheme = SchemeBuilder.AddToScheme ) -// Composition type metadata. +// EnvironmentConfig type metadata. var ( EnvironmentConfigKind = reflect.TypeOf(EnvironmentConfig{}).Name() EnvironmentConfigGroupKind = schema.GroupKind{Group: Group, Kind: EnvironmentConfigKind}.String() diff --git a/apis/pkg/v1alpha1/function_types.go b/apis/pkg/v1alpha1/function_types.go new file mode 100644 index 000000000..bbe58f64e --- /dev/null +++ b/apis/pkg/v1alpha1/function_types.go @@ -0,0 +1,103 @@ +/* +Copyright 2023 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + + v1 "github.com/crossplane/crossplane/apis/pkg/v1" +) + +// +kubebuilder:object:root=true +// +genclient +// +genclient:nonNamespaced + +// Function is the CRD type for a request to deploy a long-running Function. +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +kubebuilder:printcolumn:name="INSTALLED",type="string",JSONPath=".status.conditions[?(@.type=='Installed')].status" +// +kubebuilder:printcolumn:name="HEALTHY",type="string",JSONPath=".status.conditions[?(@.type=='Healthy')].status" +// +kubebuilder:printcolumn:name="PACKAGE",type="string",JSONPath=".spec.package" +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:resource:scope=Cluster,categories={crossplane,pkg} +type Function struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FunctionSpec `json:"spec"` + Status FunctionStatus `json:"status"` +} + +// FunctionSpec specifies the configuration of a Function. +type FunctionSpec struct { + v1.PackageSpec `json:",inline"` +} + +// FunctionStatus represents the observed state of a Function. +type FunctionStatus struct { + xpv1.ConditionedStatus `json:",inline"` + v1.PackageStatus `json:",inline"` + + // Endpoint is the gRPC endpoint where Crossplane will send RunFunctionRequests. + Endpoint string `json:"endpoint,omitempty"` +} + +// +kubebuilder:object:root=true + +// FunctionList contains a list of Function. +type FunctionList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Function `json:"items"` +} + +// +kubebuilder:object:root=true +// +genclient +// +genclient:nonNamespaced + +// A FunctionRevision that has been added to Crossplane. +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +kubebuilder:printcolumn:name="HEALTHY",type="string",JSONPath=".status.conditions[?(@.type=='Healthy')].status" +// +kubebuilder:printcolumn:name="REVISION",type="string",JSONPath=".spec.revision" +// +kubebuilder:printcolumn:name="IMAGE",type="string",JSONPath=".spec.image" +// +kubebuilder:printcolumn:name="STATE",type="string",JSONPath=".spec.desiredState" +// +kubebuilder:printcolumn:name="DEP-FOUND",type="string",JSONPath=".status.foundDependencies" +// +kubebuilder:printcolumn:name="DEP-INSTALLED",type="string",JSONPath=".status.installedDependencies" +// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" +// +kubebuilder:resource:scope=Cluster,categories={crossplane,pkgrev} +type FunctionRevision struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec v1.PackageRevisionSpec `json:"spec,omitempty"` + Status v1.PackageRevisionStatus `json:"status,omitempty"` + + // Endpoint is the gRPC endpoint where Crossplane will send RunFunctionRequests. + Endpoint string `json:"endpoint,omitempty"` +} + +// +kubebuilder:object:root=true + +// FunctionRevisionList contains a list of FunctionRevision. +type FunctionRevisionList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FunctionRevision `json:"items"` +} diff --git a/apis/pkg/v1alpha1/register.go b/apis/pkg/v1alpha1/register.go index 63509f215..ff36fccf3 100644 --- a/apis/pkg/v1alpha1/register.go +++ b/apis/pkg/v1alpha1/register.go @@ -48,6 +48,14 @@ var ( ControllerConfigGroupVersionKind = SchemeGroupVersion.WithKind(ControllerConfigKind) ) +// Function type metadata. +var ( + FunctionRevisionKind = reflect.TypeOf(FunctionRevision{}).Name() + FunctionRevisionGroupKind = schema.GroupKind{Group: Group, Kind: FunctionRevisionKind}.String() + FunctionRevisionKindAPIVersion = FunctionRevisionKind + "." + SchemeGroupVersion.String() + FunctionRevisionGroupVersionKind = SchemeGroupVersion.WithKind(FunctionRevisionKind) +) + func init() { SchemeBuilder.Register(&ControllerConfig{}, &ControllerConfigList{}) } diff --git a/apis/pkg/v1alpha1/zz_generated.deepcopy.go b/apis/pkg/v1alpha1/zz_generated.deepcopy.go index 9e79d2c3c..b10b22aef 100644 --- a/apis/pkg/v1alpha1/zz_generated.deepcopy.go +++ b/apis/pkg/v1alpha1/zz_generated.deepcopy.go @@ -216,6 +216,157 @@ func (in *ControllerConfigSpec) DeepCopy() *ControllerConfigSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Function) DeepCopyInto(out *Function) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. +func (in *Function) DeepCopy() *Function { + if in == nil { + return nil + } + out := new(Function) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Function) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionList) DeepCopyInto(out *FunctionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Function, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionList. +func (in *FunctionList) DeepCopy() *FunctionList { + if in == nil { + return nil + } + out := new(FunctionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FunctionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionRevision) DeepCopyInto(out *FunctionRevision) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionRevision. +func (in *FunctionRevision) DeepCopy() *FunctionRevision { + if in == nil { + return nil + } + out := new(FunctionRevision) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FunctionRevision) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionRevisionList) DeepCopyInto(out *FunctionRevisionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FunctionRevision, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionRevisionList. +func (in *FunctionRevisionList) DeepCopy() *FunctionRevisionList { + if in == nil { + return nil + } + out := new(FunctionRevisionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FunctionRevisionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) { + *out = *in + in.PackageSpec.DeepCopyInto(&out.PackageSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec. +func (in *FunctionSpec) DeepCopy() *FunctionSpec { + if in == nil { + return nil + } + out := new(FunctionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FunctionStatus) DeepCopyInto(out *FunctionStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) + out.PackageStatus = in.PackageStatus +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionStatus. +func (in *FunctionStatus) DeepCopy() *FunctionStatus { + if in == nil { + return nil + } + out := new(FunctionStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodObjectMeta) DeepCopyInto(out *PodObjectMeta) { *out = *in diff --git a/cluster/crds/pkg.crossplane.io_functionrevisions.yaml b/cluster/crds/pkg.crossplane.io_functionrevisions.yaml new file mode 100644 index 000000000..90fc22331 --- /dev/null +++ b/cluster/crds/pkg.crossplane.io_functionrevisions.yaml @@ -0,0 +1,287 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: functionrevisions.pkg.crossplane.io +spec: + group: pkg.crossplane.io + names: + categories: + - crossplane + - pkgrev + kind: FunctionRevision + listKind: FunctionRevisionList + plural: functionrevisions + singular: functionrevision + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Healthy')].status + name: HEALTHY + type: string + - jsonPath: .spec.revision + name: REVISION + type: string + - jsonPath: .spec.image + name: IMAGE + type: string + - jsonPath: .spec.desiredState + name: STATE + type: string + - jsonPath: .status.foundDependencies + name: DEP-FOUND + type: string + - jsonPath: .status.installedDependencies + name: DEP-INSTALLED + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: A FunctionRevision that has been added to Crossplane. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + endpoint: + description: Endpoint is the gRPC endpoint where Crossplane will send + RunFunctionRequests. + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PackageRevisionSpec specifies the desired state of a PackageRevision. + properties: + commonLabels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used to organize + and categorize (scope and select) objects. May match selectors of + replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + controllerConfigRef: + description: ControllerConfigRef references a ControllerConfig resource + that will be used to configure the packaged controller Deployment. + properties: + name: + description: Name of the ControllerConfig. + type: string + required: + - name + type: object + desiredState: + description: DesiredState of the PackageRevision. Can be either Active + or Inactive. + type: string + essTLSSecretName: + description: ESSTLSSecretName is the secret name of the TLS certificates + that will be used by the provider for External Secret Stores. + type: string + ignoreCrossplaneConstraints: + default: false + description: IgnoreCrossplaneConstraints indicates to the package + manager whether to honor Crossplane version constrains specified + by the package. Default is false. + type: boolean + image: + description: Package image used by install Pod to extract package + contents. + type: string + packagePullPolicy: + default: IfNotPresent + description: PackagePullPolicy defines the pull policy for the package. + It is also applied to any images pulled for the package, such as + a provider's controller image. Default is IfNotPresent. + type: string + packagePullSecrets: + description: PackagePullSecrets are named secrets in the same namespace + that can be used to fetch packages from private registries. They + are also applied to any images pulled for the package, such as a + provider's controller image. + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + revision: + description: Revision number. Indicates when the revision will be + garbage collected based on the parent's RevisionHistoryLimit. + format: int64 + type: integer + skipDependencyResolution: + default: false + description: SkipDependencyResolution indicates to the package manager + whether to skip resolving dependencies for a package. Setting this + value to true may have unintended consequences. Default is false. + type: boolean + webhookTLSSecretName: + description: WebhookTLSSecretName is the name of the TLS Secret that + will be used by the provider to serve a TLS-enabled webhook server. + The certificate will be injected to webhook configurations as well + as CRD conversion webhook strategy if needed. If it's not given, + provider will not have a certificate mounted to its filesystem, + webhook configurations won't be deployed and if there is a CRD with + webhook conversion strategy, the installation will fail. + type: string + required: + - desiredState + - image + - revision + type: object + status: + description: PackageRevisionStatus represents the observed state of a + PackageRevision. + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown? + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + controllerRef: + description: ControllerRef references the controller (e.g. Deployment), + if any, that is responsible for reconciling the objects this package + revision installed. + properties: + name: + description: Name of the controller. + type: string + required: + - name + type: object + foundDependencies: + description: Dependency information. + format: int64 + type: integer + installedDependencies: + format: int64 + type: integer + invalidDependencies: + format: int64 + type: integer + objectRefs: + description: References to objects owned by PackageRevision. + items: + description: A TypedReference refers to an object by Name, Kind, + and APIVersion. It is commonly used to reference cluster-scoped + objects or objects where the namespace is already known. + properties: + apiVersion: + description: APIVersion of the referenced object. + type: string + kind: + description: Kind of the referenced object. + type: string + name: + description: Name of the referenced object. + type: string + uid: + description: UID of the referenced object. + type: string + required: + - apiVersion + - kind + - name + type: object + type: array + permissionRequests: + description: PermissionRequests made by this package. The package + declares that its controller needs these permissions to run. The + RBAC manager is responsible for granting them. + items: + description: PolicyRule holds information that describes a policy + rule, but does not contain information about who the rule applies + to or which namespace the rule applies to. + properties: + apiGroups: + description: APIGroups is the name of the APIGroup that contains + the resources. If multiple API groups are specified, any + action requested against one of the enumerated resources in + any API group will be allowed. "" represents the core API + group and "*" represents all API groups. + items: + type: string + type: array + nonResourceURLs: + description: NonResourceURLs is a set of partial urls that a + user should have access to. *s are allowed, but only as the + full, final step in the path Since non-resource URLs are not + namespaced, this field is only applicable for ClusterRoles + referenced from a ClusterRoleBinding. Rules can either apply + to API resources (such as "pods" or "secrets") or non-resource + URL paths (such as "/api"), but not both. + items: + type: string + type: array + resourceNames: + description: ResourceNames is an optional white list of names + that the rule applies to. An empty set means that everything + is allowed. + items: + type: string + type: array + resources: + description: Resources is a list of resources this rule applies + to. '*' represents all resources. + items: + type: string + type: array + verbs: + description: Verbs is a list of Verbs that apply to ALL the + ResourceKinds contained in this rule. '*' represents all verbs. + items: + type: string + type: array + required: + - verbs + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/cluster/crds/pkg.crossplane.io_functions.yaml b/cluster/crds/pkg.crossplane.io_functions.yaml new file mode 100644 index 000000000..4c154d86d --- /dev/null +++ b/cluster/crds/pkg.crossplane.io_functions.yaml @@ -0,0 +1,171 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: functions.pkg.crossplane.io +spec: + group: pkg.crossplane.io + names: + categories: + - crossplane + - pkg + kind: Function + listKind: FunctionList + plural: functions + singular: function + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Installed')].status + name: INSTALLED + type: string + - jsonPath: .status.conditions[?(@.type=='Healthy')].status + name: HEALTHY + type: string + - jsonPath: .spec.package + name: PACKAGE + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Function is the CRD type for a request to deploy a long-running + Function. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: FunctionSpec specifies the configuration of a Function. + properties: + commonLabels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used to organize + and categorize (scope and select) objects. May match selectors of + replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + ignoreCrossplaneConstraints: + default: false + description: IgnoreCrossplaneConstraints indicates to the package + manager whether to honor Crossplane version constrains specified + by the package. Default is false. + type: boolean + package: + description: Package is the name of the package that is being requested. + type: string + packagePullPolicy: + default: IfNotPresent + description: PackagePullPolicy defines the pull policy for the package. + Default is IfNotPresent. + type: string + packagePullSecrets: + description: PackagePullSecrets are named secrets in the same namespace + that can be used to fetch packages from private registries. + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + revisionActivationPolicy: + default: Automatic + description: RevisionActivationPolicy specifies how the package controller + should update from one revision to the next. Options are Automatic + or Manual. Default is Automatic. + type: string + revisionHistoryLimit: + default: 1 + description: RevisionHistoryLimit dictates how the package controller + cleans up old inactive package revisions. Defaults to 1. Can be + disabled by explicitly setting to 0. + format: int64 + type: integer + skipDependencyResolution: + default: false + description: SkipDependencyResolution indicates to the package manager + whether to skip resolving dependencies for a package. Setting this + value to true may have unintended consequences. Default is false. + type: boolean + required: + - package + type: object + status: + description: FunctionStatus represents the observed state of a Function. + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown? + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + currentIdentifier: + description: CurrentIdentifier is the most recent package source that + was used to produce a revision. The package manager uses this field + to determine whether to check for package updates for a given source + when packagePullPolicy is set to IfNotPresent. Manually removing + this field will cause the package manager to check that the current + revision is correct for the given package source. + type: string + currentRevision: + description: CurrentRevision is the name of the current package revision. + It will reflect the most up to date revision, whether it has been + activated or not. + type: string + endpoint: + description: Endpoint is the gRPC endpoint where Crossplane will send + RunFunctionRequests. + type: string + type: object + required: + - spec + - status + type: object + served: true + storage: true + subresources: + status: {} diff --git a/cluster/kustomization.yaml b/cluster/kustomization.yaml index 95ac09ad3..201efc3bc 100644 --- a/cluster/kustomization.yaml +++ b/cluster/kustomization.yaml @@ -8,6 +8,8 @@ resources: - crds/pkg.crossplane.io_configurationrevisions.yaml - crds/pkg.crossplane.io_configurations.yaml - crds/pkg.crossplane.io_controllerconfigs.yaml +- crds/pkg.crossplane.io_functionrevisions.yaml +- crds/pkg.crossplane.io_functions.yaml - crds/pkg.crossplane.io_locks.yaml - crds/pkg.crossplane.io_providerrevisions.yaml - crds/pkg.crossplane.io_providers.yaml diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_function.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_function.go new file mode 100644 index 000000000..460074ec8 --- /dev/null +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_function.go @@ -0,0 +1,132 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/crossplane/crossplane/apis/pkg/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeFunctions implements FunctionInterface +type FakeFunctions struct { + Fake *FakePkgV1alpha1 +} + +var functionsResource = v1alpha1.SchemeGroupVersion.WithResource("functions") + +var functionsKind = v1alpha1.SchemeGroupVersion.WithKind("Function") + +// Get takes name of the function, and returns the corresponding function object, and an error if there is any. +func (c *FakeFunctions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Function, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(functionsResource, name), &v1alpha1.Function{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Function), err +} + +// List takes label and field selectors, and returns the list of Functions that match those selectors. +func (c *FakeFunctions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FunctionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(functionsResource, functionsKind, opts), &v1alpha1.FunctionList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.FunctionList{ListMeta: obj.(*v1alpha1.FunctionList).ListMeta} + for _, item := range obj.(*v1alpha1.FunctionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested functions. +func (c *FakeFunctions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(functionsResource, opts)) +} + +// Create takes the representation of a function and creates it. Returns the server's representation of the function, and an error, if there is any. +func (c *FakeFunctions) Create(ctx context.Context, function *v1alpha1.Function, opts v1.CreateOptions) (result *v1alpha1.Function, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(functionsResource, function), &v1alpha1.Function{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Function), err +} + +// Update takes the representation of a function and updates it. Returns the server's representation of the function, and an error, if there is any. +func (c *FakeFunctions) Update(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (result *v1alpha1.Function, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(functionsResource, function), &v1alpha1.Function{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Function), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeFunctions) UpdateStatus(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (*v1alpha1.Function, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(functionsResource, "status", function), &v1alpha1.Function{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Function), err +} + +// Delete takes name of the function and deletes it. Returns an error if one occurs. +func (c *FakeFunctions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(functionsResource, name, opts), &v1alpha1.Function{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFunctions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(functionsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.FunctionList{}) + return err +} + +// Patch applies the patch and returns the patched function. +func (c *FakeFunctions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Function, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(functionsResource, name, pt, data, subresources...), &v1alpha1.Function{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Function), err +} diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_functionrevision.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_functionrevision.go new file mode 100644 index 000000000..24b681eac --- /dev/null +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_functionrevision.go @@ -0,0 +1,132 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/crossplane/crossplane/apis/pkg/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeFunctionRevisions implements FunctionRevisionInterface +type FakeFunctionRevisions struct { + Fake *FakePkgV1alpha1 +} + +var functionrevisionsResource = v1alpha1.SchemeGroupVersion.WithResource("functionrevisions") + +var functionrevisionsKind = v1alpha1.SchemeGroupVersion.WithKind("FunctionRevision") + +// Get takes name of the functionRevision, and returns the corresponding functionRevision object, and an error if there is any. +func (c *FakeFunctionRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.FunctionRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(functionrevisionsResource, name), &v1alpha1.FunctionRevision{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FunctionRevision), err +} + +// List takes label and field selectors, and returns the list of FunctionRevisions that match those selectors. +func (c *FakeFunctionRevisions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FunctionRevisionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(functionrevisionsResource, functionrevisionsKind, opts), &v1alpha1.FunctionRevisionList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.FunctionRevisionList{ListMeta: obj.(*v1alpha1.FunctionRevisionList).ListMeta} + for _, item := range obj.(*v1alpha1.FunctionRevisionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested functionRevisions. +func (c *FakeFunctionRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(functionrevisionsResource, opts)) +} + +// Create takes the representation of a functionRevision and creates it. Returns the server's representation of the functionRevision, and an error, if there is any. +func (c *FakeFunctionRevisions) Create(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.CreateOptions) (result *v1alpha1.FunctionRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(functionrevisionsResource, functionRevision), &v1alpha1.FunctionRevision{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FunctionRevision), err +} + +// Update takes the representation of a functionRevision and updates it. Returns the server's representation of the functionRevision, and an error, if there is any. +func (c *FakeFunctionRevisions) Update(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.UpdateOptions) (result *v1alpha1.FunctionRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(functionrevisionsResource, functionRevision), &v1alpha1.FunctionRevision{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FunctionRevision), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeFunctionRevisions) UpdateStatus(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.UpdateOptions) (*v1alpha1.FunctionRevision, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(functionrevisionsResource, "status", functionRevision), &v1alpha1.FunctionRevision{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FunctionRevision), err +} + +// Delete takes name of the functionRevision and deletes it. Returns an error if one occurs. +func (c *FakeFunctionRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(functionrevisionsResource, name, opts), &v1alpha1.FunctionRevision{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeFunctionRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(functionrevisionsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.FunctionRevisionList{}) + return err +} + +// Patch applies the patch and returns the patched functionRevision. +func (c *FakeFunctionRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.FunctionRevision, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(functionrevisionsResource, name, pt, data, subresources...), &v1alpha1.FunctionRevision{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.FunctionRevision), err +} diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_pkg_client.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_pkg_client.go index ffc844254..29cbd0121 100644 --- a/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_pkg_client.go +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/fake/fake_pkg_client.go @@ -32,6 +32,14 @@ func (c *FakePkgV1alpha1) ControllerConfigs() v1alpha1.ControllerConfigInterface return &FakeControllerConfigs{c} } +func (c *FakePkgV1alpha1) Functions() v1alpha1.FunctionInterface { + return &FakeFunctions{c} +} + +func (c *FakePkgV1alpha1) FunctionRevisions() v1alpha1.FunctionRevisionInterface { + return &FakeFunctionRevisions{c} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakePkgV1alpha1) RESTClient() rest.Interface { diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/function.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/function.go new file mode 100644 index 000000000..7b16c6e36 --- /dev/null +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/function.go @@ -0,0 +1,184 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/crossplane/crossplane/apis/pkg/v1alpha1" + scheme "github.com/crossplane/crossplane/internal/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// FunctionsGetter has a method to return a FunctionInterface. +// A group's client should implement this interface. +type FunctionsGetter interface { + Functions() FunctionInterface +} + +// FunctionInterface has methods to work with Function resources. +type FunctionInterface interface { + Create(ctx context.Context, function *v1alpha1.Function, opts v1.CreateOptions) (*v1alpha1.Function, error) + Update(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (*v1alpha1.Function, error) + UpdateStatus(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (*v1alpha1.Function, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.Function, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.FunctionList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Function, err error) + FunctionExpansion +} + +// functions implements FunctionInterface +type functions struct { + client rest.Interface +} + +// newFunctions returns a Functions +func newFunctions(c *PkgV1alpha1Client) *functions { + return &functions{ + client: c.RESTClient(), + } +} + +// Get takes name of the function, and returns the corresponding function object, and an error if there is any. +func (c *functions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Function, err error) { + result = &v1alpha1.Function{} + err = c.client.Get(). + Resource("functions"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Functions that match those selectors. +func (c *functions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FunctionList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.FunctionList{} + err = c.client.Get(). + Resource("functions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested functions. +func (c *functions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("functions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a function and creates it. Returns the server's representation of the function, and an error, if there is any. +func (c *functions) Create(ctx context.Context, function *v1alpha1.Function, opts v1.CreateOptions) (result *v1alpha1.Function, err error) { + result = &v1alpha1.Function{} + err = c.client.Post(). + Resource("functions"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(function). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a function and updates it. Returns the server's representation of the function, and an error, if there is any. +func (c *functions) Update(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (result *v1alpha1.Function, err error) { + result = &v1alpha1.Function{} + err = c.client.Put(). + Resource("functions"). + Name(function.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(function). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *functions) UpdateStatus(ctx context.Context, function *v1alpha1.Function, opts v1.UpdateOptions) (result *v1alpha1.Function, err error) { + result = &v1alpha1.Function{} + err = c.client.Put(). + Resource("functions"). + Name(function.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(function). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the function and deletes it. Returns an error if one occurs. +func (c *functions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("functions"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *functions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("functions"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched function. +func (c *functions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Function, err error) { + result = &v1alpha1.Function{} + err = c.client.Patch(pt). + Resource("functions"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/functionrevision.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/functionrevision.go new file mode 100644 index 000000000..263ee91a7 --- /dev/null +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/functionrevision.go @@ -0,0 +1,184 @@ +/* +Copyright 2021 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/crossplane/crossplane/apis/pkg/v1alpha1" + scheme "github.com/crossplane/crossplane/internal/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// FunctionRevisionsGetter has a method to return a FunctionRevisionInterface. +// A group's client should implement this interface. +type FunctionRevisionsGetter interface { + FunctionRevisions() FunctionRevisionInterface +} + +// FunctionRevisionInterface has methods to work with FunctionRevision resources. +type FunctionRevisionInterface interface { + Create(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.CreateOptions) (*v1alpha1.FunctionRevision, error) + Update(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.UpdateOptions) (*v1alpha1.FunctionRevision, error) + UpdateStatus(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.UpdateOptions) (*v1alpha1.FunctionRevision, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.FunctionRevision, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.FunctionRevisionList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.FunctionRevision, err error) + FunctionRevisionExpansion +} + +// functionRevisions implements FunctionRevisionInterface +type functionRevisions struct { + client rest.Interface +} + +// newFunctionRevisions returns a FunctionRevisions +func newFunctionRevisions(c *PkgV1alpha1Client) *functionRevisions { + return &functionRevisions{ + client: c.RESTClient(), + } +} + +// Get takes name of the functionRevision, and returns the corresponding functionRevision object, and an error if there is any. +func (c *functionRevisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.FunctionRevision, err error) { + result = &v1alpha1.FunctionRevision{} + err = c.client.Get(). + Resource("functionrevisions"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of FunctionRevisions that match those selectors. +func (c *functionRevisions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FunctionRevisionList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.FunctionRevisionList{} + err = c.client.Get(). + Resource("functionrevisions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested functionRevisions. +func (c *functionRevisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("functionrevisions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a functionRevision and creates it. Returns the server's representation of the functionRevision, and an error, if there is any. +func (c *functionRevisions) Create(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.CreateOptions) (result *v1alpha1.FunctionRevision, err error) { + result = &v1alpha1.FunctionRevision{} + err = c.client.Post(). + Resource("functionrevisions"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(functionRevision). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a functionRevision and updates it. Returns the server's representation of the functionRevision, and an error, if there is any. +func (c *functionRevisions) Update(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.UpdateOptions) (result *v1alpha1.FunctionRevision, err error) { + result = &v1alpha1.FunctionRevision{} + err = c.client.Put(). + Resource("functionrevisions"). + Name(functionRevision.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(functionRevision). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *functionRevisions) UpdateStatus(ctx context.Context, functionRevision *v1alpha1.FunctionRevision, opts v1.UpdateOptions) (result *v1alpha1.FunctionRevision, err error) { + result = &v1alpha1.FunctionRevision{} + err = c.client.Put(). + Resource("functionrevisions"). + Name(functionRevision.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(functionRevision). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the functionRevision and deletes it. Returns an error if one occurs. +func (c *functionRevisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("functionrevisions"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *functionRevisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("functionrevisions"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched functionRevision. +func (c *functionRevisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.FunctionRevision, err error) { + result = &v1alpha1.FunctionRevision{} + err = c.client.Patch(pt). + Resource("functionrevisions"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/generated_expansion.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/generated_expansion.go index f6fcd2b95..7ffe4b2d4 100644 --- a/internal/client/clientset/versioned/typed/pkg/v1alpha1/generated_expansion.go +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/generated_expansion.go @@ -19,3 +19,7 @@ limitations under the License. package v1alpha1 type ControllerConfigExpansion interface{} + +type FunctionExpansion interface{} + +type FunctionRevisionExpansion interface{} diff --git a/internal/client/clientset/versioned/typed/pkg/v1alpha1/pkg_client.go b/internal/client/clientset/versioned/typed/pkg/v1alpha1/pkg_client.go index 8679b8b28..f48314a0f 100644 --- a/internal/client/clientset/versioned/typed/pkg/v1alpha1/pkg_client.go +++ b/internal/client/clientset/versioned/typed/pkg/v1alpha1/pkg_client.go @@ -29,6 +29,8 @@ import ( type PkgV1alpha1Interface interface { RESTClient() rest.Interface ControllerConfigsGetter + FunctionsGetter + FunctionRevisionsGetter } // PkgV1alpha1Client is used to interact with features provided by the pkg.crossplane.io group. @@ -40,6 +42,14 @@ func (c *PkgV1alpha1Client) ControllerConfigs() ControllerConfigInterface { return newControllerConfigs(c) } +func (c *PkgV1alpha1Client) Functions() FunctionInterface { + return newFunctions(c) +} + +func (c *PkgV1alpha1Client) FunctionRevisions() FunctionRevisionInterface { + return newFunctionRevisions(c) +} + // NewForConfig creates a new PkgV1alpha1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). From df9918254064a52c26ef541d1b8eef84dfce714f Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Wed, 2 Aug 2023 13:37:30 +0200 Subject: [PATCH 136/148] feat: add xfn v1beta1 grpc interface Signed-off-by: Philippe Scorsolini --- .../fn/proto/v1beta1/run_function.pb.go | 815 ++++++++++++++++++ .../fn/proto/v1beta1/run_function.proto | 131 +++ .../fn/proto/v1beta1/run_function_grpc.pb.go | 126 +++ 3 files changed, 1072 insertions(+) create mode 100644 apis/apiextensions/fn/proto/v1beta1/run_function.pb.go create mode 100644 apis/apiextensions/fn/proto/v1beta1/run_function.proto create mode 100644 apis/apiextensions/fn/proto/v1beta1/run_function_grpc.pb.go diff --git a/apis/apiextensions/fn/proto/v1beta1/run_function.pb.go b/apis/apiextensions/fn/proto/v1beta1/run_function.pb.go new file mode 100644 index 000000000..59035f05e --- /dev/null +++ b/apis/apiextensions/fn/proto/v1beta1/run_function.pb.go @@ -0,0 +1,815 @@ +// +//Copyright 2022 The Crossplane Authors. +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: apiextensions/fn/proto/v1beta1/run_function.proto + +package v1beta1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Severity of Function results. +type Severity int32 + +const ( + Severity_SEVERITY_UNSPECIFIED Severity = 0 + // Fatal results are fatal; subsequent Composition Functions may run, but + // the Composition Function pipeline run will be considered a failure and + // the first fatal result will be returned as an error. + Severity_SEVERITY_FATAL Severity = 1 + // Warning results are non-fatal; the entire Composition will run to + // completion but warning events and debug logs associated with the + // composite resource will be emitted. + Severity_SEVERITY_WARNING Severity = 2 + // Normal results are emitted as normal events and debug logs associated + // with the composite resource. + Severity_SEVERITY_NORMAL Severity = 3 +) + +// Enum value maps for Severity. +var ( + Severity_name = map[int32]string{ + 0: "SEVERITY_UNSPECIFIED", + 1: "SEVERITY_FATAL", + 2: "SEVERITY_WARNING", + 3: "SEVERITY_NORMAL", + } + Severity_value = map[string]int32{ + "SEVERITY_UNSPECIFIED": 0, + "SEVERITY_FATAL": 1, + "SEVERITY_WARNING": 2, + "SEVERITY_NORMAL": 3, + } +) + +func (x Severity) Enum() *Severity { + p := new(Severity) + *p = x + return p +} + +func (x Severity) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Severity) Descriptor() protoreflect.EnumDescriptor { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_enumTypes[0].Descriptor() +} + +func (Severity) Type() protoreflect.EnumType { + return &file_apiextensions_fn_proto_v1beta1_run_function_proto_enumTypes[0] +} + +func (x Severity) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Severity.Descriptor instead. +func (Severity) EnumDescriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{0} +} + +// A RunFunctionRequest requests that the Composition Function be run. +type RunFunctionRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Metadata pertaining to this request. + Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + // The observed state prior to invocation of a Function pipeline. State passed + // to each Function is fresh as of the time the pipeline was invoked, not as + // of the time each Function was invoked. + Observed *State `protobuf:"bytes,2,opt,name=observed,proto3" json:"observed,omitempty"` + // Desired state according to a Function pipeline. The state passed to a + // particular Function may have been accumulated by processing a Composition's + // patch-and-transform resources array. It may also have been accumulated by + // previous Functions in the pipeline. + Desired *State `protobuf:"bytes,3,opt,name=desired,proto3" json:"desired,omitempty"` + // Optional input specific to this Function invocation. A JSON representation + // of the 'input' block of the relevant entry in a Composition's pipeline. + Input *structpb.Struct `protobuf:"bytes,4,opt,name=input,proto3,oneof" json:"input,omitempty"` +} + +func (x *RunFunctionRequest) Reset() { + *x = RunFunctionRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RunFunctionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RunFunctionRequest) ProtoMessage() {} + +func (x *RunFunctionRequest) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RunFunctionRequest.ProtoReflect.Descriptor instead. +func (*RunFunctionRequest) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{0} +} + +func (x *RunFunctionRequest) GetMeta() *RequestMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *RunFunctionRequest) GetObserved() *State { + if x != nil { + return x.Observed + } + return nil +} + +func (x *RunFunctionRequest) GetDesired() *State { + if x != nil { + return x.Desired + } + return nil +} + +func (x *RunFunctionRequest) GetInput() *structpb.Struct { + if x != nil { + return x.Input + } + return nil +} + +// A RunFunctionResponse contains the result of a Composition Function run. +type RunFunctionResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Metadata pertaining to this response. + Meta *ResponseMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` + // Desired state according to a Function pipeline. Functions may add desired + // state, and may mutate or delete any part of the desired state they are + // concerned with. A Function must pass through any part of the desired state + // that it is not concerned with. + Desired *State `protobuf:"bytes,2,opt,name=desired,proto3" json:"desired,omitempty"` + // Results of the Function run. Results are used for observability purposes. + Results []*Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"` +} + +func (x *RunFunctionResponse) Reset() { + *x = RunFunctionResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RunFunctionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RunFunctionResponse) ProtoMessage() {} + +func (x *RunFunctionResponse) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RunFunctionResponse.ProtoReflect.Descriptor instead. +func (*RunFunctionResponse) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{1} +} + +func (x *RunFunctionResponse) GetMeta() *ResponseMeta { + if x != nil { + return x.Meta + } + return nil +} + +func (x *RunFunctionResponse) GetDesired() *State { + if x != nil { + return x.Desired + } + return nil +} + +func (x *RunFunctionResponse) GetResults() []*Result { + if x != nil { + return x.Results + } + return nil +} + +// RequestMeta contains metadata pertaining to a RunFunctionRequest. +type RequestMeta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // An opaque string identifying the content of the request. Two identical + // requests should have the same tag. + Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` +} + +func (x *RequestMeta) Reset() { + *x = RequestMeta{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestMeta) ProtoMessage() {} + +func (x *RequestMeta) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestMeta.ProtoReflect.Descriptor instead. +func (*RequestMeta) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{2} +} + +func (x *RequestMeta) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +// ResponseMeta contains metadata pertaining to a RunFunctionResponse. +type ResponseMeta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // An opaque string identifying the content of the request. Must match the + // meta.tag of the corresponding RunFunctionRequest. + Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` + // Time-to-live of this response. Deterministic Functions with no side-effects + // (e.g. simple templating Functions) may specify a TTL. Crossplane may choose + // to cache responses until the TTL expires. + Ttl *durationpb.Duration `protobuf:"bytes,2,opt,name=ttl,proto3,oneof" json:"ttl,omitempty"` +} + +func (x *ResponseMeta) Reset() { + *x = ResponseMeta{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResponseMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResponseMeta) ProtoMessage() {} + +func (x *ResponseMeta) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResponseMeta.ProtoReflect.Descriptor instead. +func (*ResponseMeta) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{3} +} + +func (x *ResponseMeta) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +func (x *ResponseMeta) GetTtl() *durationpb.Duration { + if x != nil { + return x.Ttl + } + return nil +} + +// State of the composite resource (XR) and any composed resources. +type State struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The state of the composite resource (XR). + Composite *Resource `protobuf:"bytes,1,opt,name=composite,proto3" json:"composite,omitempty"` + // The state of any composed resources. + Resources map[string]*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *State) Reset() { + *x = State{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *State) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*State) ProtoMessage() {} + +func (x *State) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use State.ProtoReflect.Descriptor instead. +func (*State) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{4} +} + +func (x *State) GetComposite() *Resource { + if x != nil { + return x.Composite + } + return nil +} + +func (x *State) GetResources() map[string]*Resource { + if x != nil { + return x.Resources + } + return nil +} + +// A Resource represents the state of a resource. +type Resource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The JSON representation of the resource. + Resource *structpb.Struct `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + // The resource's connection details. + ConnectionDetails map[string][]byte `protobuf:"bytes,2,rep,name=connection_details,json=connectionDetails,proto3" json:"connection_details,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Resource) Reset() { + *x = Resource{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Resource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Resource) ProtoMessage() {} + +func (x *Resource) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Resource.ProtoReflect.Descriptor instead. +func (*Resource) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{5} +} + +func (x *Resource) GetResource() *structpb.Struct { + if x != nil { + return x.Resource + } + return nil +} + +func (x *Resource) GetConnectionDetails() map[string][]byte { + if x != nil { + return x.ConnectionDetails + } + return nil +} + +// A Result of running a Function. +type Result struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Severity of this result. + Severity Severity `protobuf:"varint,1,opt,name=severity,proto3,enum=apiextensions.fn.proto.v1beta1.Severity" json:"severity,omitempty"` + // Human-readable details about the result. + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *Result) Reset() { + *x = Result{} + if protoimpl.UnsafeEnabled { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Result) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Result) ProtoMessage() {} + +func (x *Result) ProtoReflect() protoreflect.Message { + mi := &file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Result.ProtoReflect.Descriptor instead. +func (*Result) Descriptor() ([]byte, []int) { + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP(), []int{6} +} + +func (x *Result) GetSeverity() Severity { + if x != nil { + return x.Severity + } + return Severity_SEVERITY_UNSPECIFIED +} + +func (x *Result) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_apiextensions_fn_proto_v1beta1_run_function_proto protoreflect.FileDescriptor + +var file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDesc = []byte{ + 0x0a, 0x31, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, + 0x66, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x72, 0x75, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x97, 0x02, 0x0a, 0x12, 0x52, 0x75, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x08, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x70, + 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x12, 0x3f, 0x0a, 0x07, + 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x07, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x12, 0x32, 0x0a, + 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x88, 0x01, + 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0xda, 0x01, 0x0a, 0x13, + 0x52, 0x75, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x07, 0x64, + 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x12, 0x40, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x1f, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x5a, 0x0a, 0x0c, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x30, 0x0a, 0x03, 0x74, + 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, + 0x04, 0x5f, 0x74, 0x74, 0x6c, 0x22, 0x8b, 0x02, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x46, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x63, 0x6f, + 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x61, 0x70, 0x69, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0x66, 0x0a, 0x0e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0xf5, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x33, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x08, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x6e, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x3f, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x44, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x68, 0x0a, 0x06, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x63, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, + 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x01, 0x12, + 0x14, 0x0a, 0x10, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x57, 0x41, 0x52, 0x4e, + 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x56, 0x45, 0x52, 0x49, 0x54, + 0x59, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x03, 0x32, 0x91, 0x01, 0x0a, 0x15, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x78, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x46, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x46, + 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6f, + 0x73, 0x73, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x66, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescOnce sync.Once + file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescData = file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDesc +) + +func file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescGZIP() []byte { + file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescOnce.Do(func() { + file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescData = protoimpl.X.CompressGZIP(file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescData) + }) + return file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDescData +} + +var file_apiextensions_fn_proto_v1beta1_run_function_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_apiextensions_fn_proto_v1beta1_run_function_proto_goTypes = []interface{}{ + (Severity)(0), // 0: apiextensions.fn.proto.v1beta1.Severity + (*RunFunctionRequest)(nil), // 1: apiextensions.fn.proto.v1beta1.RunFunctionRequest + (*RunFunctionResponse)(nil), // 2: apiextensions.fn.proto.v1beta1.RunFunctionResponse + (*RequestMeta)(nil), // 3: apiextensions.fn.proto.v1beta1.RequestMeta + (*ResponseMeta)(nil), // 4: apiextensions.fn.proto.v1beta1.ResponseMeta + (*State)(nil), // 5: apiextensions.fn.proto.v1beta1.State + (*Resource)(nil), // 6: apiextensions.fn.proto.v1beta1.Resource + (*Result)(nil), // 7: apiextensions.fn.proto.v1beta1.Result + nil, // 8: apiextensions.fn.proto.v1beta1.State.ResourcesEntry + nil, // 9: apiextensions.fn.proto.v1beta1.Resource.ConnectionDetailsEntry + (*structpb.Struct)(nil), // 10: google.protobuf.Struct + (*durationpb.Duration)(nil), // 11: google.protobuf.Duration +} +var file_apiextensions_fn_proto_v1beta1_run_function_proto_depIdxs = []int32{ + 3, // 0: apiextensions.fn.proto.v1beta1.RunFunctionRequest.meta:type_name -> apiextensions.fn.proto.v1beta1.RequestMeta + 5, // 1: apiextensions.fn.proto.v1beta1.RunFunctionRequest.observed:type_name -> apiextensions.fn.proto.v1beta1.State + 5, // 2: apiextensions.fn.proto.v1beta1.RunFunctionRequest.desired:type_name -> apiextensions.fn.proto.v1beta1.State + 10, // 3: apiextensions.fn.proto.v1beta1.RunFunctionRequest.input:type_name -> google.protobuf.Struct + 4, // 4: apiextensions.fn.proto.v1beta1.RunFunctionResponse.meta:type_name -> apiextensions.fn.proto.v1beta1.ResponseMeta + 5, // 5: apiextensions.fn.proto.v1beta1.RunFunctionResponse.desired:type_name -> apiextensions.fn.proto.v1beta1.State + 7, // 6: apiextensions.fn.proto.v1beta1.RunFunctionResponse.results:type_name -> apiextensions.fn.proto.v1beta1.Result + 11, // 7: apiextensions.fn.proto.v1beta1.ResponseMeta.ttl:type_name -> google.protobuf.Duration + 6, // 8: apiextensions.fn.proto.v1beta1.State.composite:type_name -> apiextensions.fn.proto.v1beta1.Resource + 8, // 9: apiextensions.fn.proto.v1beta1.State.resources:type_name -> apiextensions.fn.proto.v1beta1.State.ResourcesEntry + 10, // 10: apiextensions.fn.proto.v1beta1.Resource.resource:type_name -> google.protobuf.Struct + 9, // 11: apiextensions.fn.proto.v1beta1.Resource.connection_details:type_name -> apiextensions.fn.proto.v1beta1.Resource.ConnectionDetailsEntry + 0, // 12: apiextensions.fn.proto.v1beta1.Result.severity:type_name -> apiextensions.fn.proto.v1beta1.Severity + 6, // 13: apiextensions.fn.proto.v1beta1.State.ResourcesEntry.value:type_name -> apiextensions.fn.proto.v1beta1.Resource + 1, // 14: apiextensions.fn.proto.v1beta1.FunctionRunnerService.RunFunction:input_type -> apiextensions.fn.proto.v1beta1.RunFunctionRequest + 2, // 15: apiextensions.fn.proto.v1beta1.FunctionRunnerService.RunFunction:output_type -> apiextensions.fn.proto.v1beta1.RunFunctionResponse + 15, // [15:16] is the sub-list for method output_type + 14, // [14:15] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_apiextensions_fn_proto_v1beta1_run_function_proto_init() } +func file_apiextensions_fn_proto_v1beta1_run_function_proto_init() { + if File_apiextensions_fn_proto_v1beta1_run_function_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RunFunctionRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RunFunctionResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResponseMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*State); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Resource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Result); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes[3].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDesc, + NumEnums: 1, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_apiextensions_fn_proto_v1beta1_run_function_proto_goTypes, + DependencyIndexes: file_apiextensions_fn_proto_v1beta1_run_function_proto_depIdxs, + EnumInfos: file_apiextensions_fn_proto_v1beta1_run_function_proto_enumTypes, + MessageInfos: file_apiextensions_fn_proto_v1beta1_run_function_proto_msgTypes, + }.Build() + File_apiextensions_fn_proto_v1beta1_run_function_proto = out.File + file_apiextensions_fn_proto_v1beta1_run_function_proto_rawDesc = nil + file_apiextensions_fn_proto_v1beta1_run_function_proto_goTypes = nil + file_apiextensions_fn_proto_v1beta1_run_function_proto_depIdxs = nil +} diff --git a/apis/apiextensions/fn/proto/v1beta1/run_function.proto b/apis/apiextensions/fn/proto/v1beta1/run_function.proto new file mode 100644 index 000000000..55588bf54 --- /dev/null +++ b/apis/apiextensions/fn/proto/v1beta1/run_function.proto @@ -0,0 +1,131 @@ +/* +Copyright 2022 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +syntax = "proto3"; + +import "google/protobuf/struct.proto"; +import "google/protobuf/duration.proto"; + +package apiextensions.fn.proto.v1beta1; + +option go_package = "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1beta1"; + +// A FunctionRunnerService is a Composition Function. +service FunctionRunnerService { + // RunFunction runs the Composition Function. + rpc RunFunction(RunFunctionRequest) returns (RunFunctionResponse) {} +} + +// A RunFunctionRequest requests that the Composition Function be run. +message RunFunctionRequest { + // Metadata pertaining to this request. + RequestMeta meta = 1; + + // The observed state prior to invocation of a Function pipeline. State passed + // to each Function is fresh as of the time the pipeline was invoked, not as + // of the time each Function was invoked. + State observed = 2; + + // Desired state according to a Function pipeline. The state passed to a + // particular Function may have been accumulated by processing a Composition's + // patch-and-transform resources array. It may also have been accumulated by + // previous Functions in the pipeline. + State desired = 3; + + // Optional input specific to this Function invocation. A JSON representation + // of the 'input' block of the relevant entry in a Composition's pipeline. + optional google.protobuf.Struct input = 4; +} + +// A RunFunctionResponse contains the result of a Composition Function run. +message RunFunctionResponse { + // Metadata pertaining to this response. + ResponseMeta meta = 1; + + // Desired state according to a Function pipeline. Functions may add desired + // state, and may mutate or delete any part of the desired state they are + // concerned with. A Function must pass through any part of the desired state + // that it is not concerned with. + State desired = 2; + + // Results of the Function run. Results are used for observability purposes. + repeated Result results = 3; +} + +// RequestMeta contains metadata pertaining to a RunFunctionRequest. +message RequestMeta { + // An opaque string identifying the content of the request. Two identical + // requests should have the same tag. + string tag = 1; +} + +// ResponseMeta contains metadata pertaining to a RunFunctionResponse. +message ResponseMeta { + // An opaque string identifying the content of the request. Must match the + // meta.tag of the corresponding RunFunctionRequest. + string tag = 1; + + // Time-to-live of this response. Deterministic Functions with no side-effects + // (e.g. simple templating Functions) may specify a TTL. Crossplane may choose + // to cache responses until the TTL expires. + optional google.protobuf.Duration ttl = 2; +} + +// State of the composite resource (XR) and any composed resources. +message State { + // The state of the composite resource (XR). + Resource composite = 1; + + // The state of any composed resources. + map resources = 2; +} + +// A Resource represents the state of a resource. +message Resource { + // The JSON representation of the resource. + google.protobuf.Struct resource = 1; + + // The resource's connection details. + map connection_details = 2; +} + +// A Result of running a Function. +message Result { + // Severity of this result. + Severity severity = 1; + + // Human-readable details about the result. + string message = 2; +} + +// Severity of Function results. +enum Severity { + SEVERITY_UNSPECIFIED = 0; + + // Fatal results are fatal; subsequent Composition Functions may run, but + // the Composition Function pipeline run will be considered a failure and + // the first fatal result will be returned as an error. + SEVERITY_FATAL = 1; + + // Warning results are non-fatal; the entire Composition will run to + // completion but warning events and debug logs associated with the + // composite resource will be emitted. + SEVERITY_WARNING = 2; + + // Normal results are emitted as normal events and debug logs associated + // with the composite resource. + SEVERITY_NORMAL = 3; +} \ No newline at end of file diff --git a/apis/apiextensions/fn/proto/v1beta1/run_function_grpc.pb.go b/apis/apiextensions/fn/proto/v1beta1/run_function_grpc.pb.go new file mode 100644 index 000000000..5ea2c19d6 --- /dev/null +++ b/apis/apiextensions/fn/proto/v1beta1/run_function_grpc.pb.go @@ -0,0 +1,126 @@ +// +//Copyright 2022 The Crossplane Authors. +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +//http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: apiextensions/fn/proto/v1beta1/run_function.proto + +package v1beta1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + FunctionRunnerService_RunFunction_FullMethodName = "/apiextensions.fn.proto.v1beta1.FunctionRunnerService/RunFunction" +) + +// FunctionRunnerServiceClient is the client API for FunctionRunnerService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type FunctionRunnerServiceClient interface { + // RunFunction runs the Composition Function. + RunFunction(ctx context.Context, in *RunFunctionRequest, opts ...grpc.CallOption) (*RunFunctionResponse, error) +} + +type functionRunnerServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewFunctionRunnerServiceClient(cc grpc.ClientConnInterface) FunctionRunnerServiceClient { + return &functionRunnerServiceClient{cc} +} + +func (c *functionRunnerServiceClient) RunFunction(ctx context.Context, in *RunFunctionRequest, opts ...grpc.CallOption) (*RunFunctionResponse, error) { + out := new(RunFunctionResponse) + err := c.cc.Invoke(ctx, FunctionRunnerService_RunFunction_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FunctionRunnerServiceServer is the server API for FunctionRunnerService service. +// All implementations must embed UnimplementedFunctionRunnerServiceServer +// for forward compatibility +type FunctionRunnerServiceServer interface { + // RunFunction runs the Composition Function. + RunFunction(context.Context, *RunFunctionRequest) (*RunFunctionResponse, error) + mustEmbedUnimplementedFunctionRunnerServiceServer() +} + +// UnimplementedFunctionRunnerServiceServer must be embedded to have forward compatible implementations. +type UnimplementedFunctionRunnerServiceServer struct { +} + +func (UnimplementedFunctionRunnerServiceServer) RunFunction(context.Context, *RunFunctionRequest) (*RunFunctionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RunFunction not implemented") +} +func (UnimplementedFunctionRunnerServiceServer) mustEmbedUnimplementedFunctionRunnerServiceServer() {} + +// UnsafeFunctionRunnerServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FunctionRunnerServiceServer will +// result in compilation errors. +type UnsafeFunctionRunnerServiceServer interface { + mustEmbedUnimplementedFunctionRunnerServiceServer() +} + +func RegisterFunctionRunnerServiceServer(s grpc.ServiceRegistrar, srv FunctionRunnerServiceServer) { + s.RegisterService(&FunctionRunnerService_ServiceDesc, srv) +} + +func _FunctionRunnerService_RunFunction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RunFunctionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FunctionRunnerServiceServer).RunFunction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FunctionRunnerService_RunFunction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FunctionRunnerServiceServer).RunFunction(ctx, req.(*RunFunctionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// FunctionRunnerService_ServiceDesc is the grpc.ServiceDesc for FunctionRunnerService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var FunctionRunnerService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "apiextensions.fn.proto.v1beta1.FunctionRunnerService", + HandlerType: (*FunctionRunnerServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RunFunction", + Handler: _FunctionRunnerService_RunFunction_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "apiextensions/fn/proto/v1beta1/run_function.proto", +} From 581e60ec10c1da0f1fdb6d28eb0bb621252ce8df Mon Sep 17 00:00:00 2001 From: Daniel Mangum Date: Wed, 2 Aug 2023 10:26:44 -0400 Subject: [PATCH 137/148] Move hasheddan to emeritus maintainers Serving as a Crossplane maintainer has been a true honor. Moving forward, I will not be able to commit the time and focus that is expected of a maintainer, and other folks have stepped up to own the areas that I have previously been leading. I am excited to step aside and watch them continue to grow and improve the project. Thank you for allowing me to be a leader in this community. Signed-off-by: Daniel Mangum --- OWNERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OWNERS.md b/OWNERS.md index 7a98796ad..352ea9b95 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -26,7 +26,6 @@ See [CODEOWNERS](CODEOWNERS) for automatic PR assignment. ## Maintainers * Nic Cope ([negz](https://github.com/negz)) -* Daniel Mangum ([hasheddan](https://github.com/hasheddan)) * Muvaffak Onus ([muvaf](https://github.com/muvaf)) * Hasan Turken ([turkenh](https://github.com/turkenh)) * Bob Haddleton ([bobh66](https://github.com/bobh66)) @@ -47,3 +46,4 @@ See [CODEOWNERS](CODEOWNERS) for automatic PR assignment. * Bassam Tabbara ([bassam](https://github.com/bassam)) * Jared Watts ([jbw976](https://github.com/jbw976)) * Illya Chekrygin ([ichekrygin](https://github.com/ichekrygin)) +* Daniel Mangum ([hasheddan](https://github.com/hasheddan)) From 3dec8d1372790d29de915fcc6069140eb9652b91 Mon Sep 17 00:00:00 2001 From: Daniel Mangum Date: Wed, 2 Aug 2023 10:39:40 -0400 Subject: [PATCH 138/148] Remove hasheddan from CODEOWNERS Replaces hasheddan with turkenh for package manager ownership, and hasheddan with negz for crank ownership. Signed-off-by: Daniel Mangum --- CODEOWNERS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 6078b36a5..dbb423e1b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -37,10 +37,10 @@ /design/ @crossplane/crossplane-maintainers @negz # Package manager -/apis/pkg/ @crossplane/crossplane-reviewers @hasheddan -/internal/xpkg/ @crossplane/crossplane-reviewers @hasheddan -/internal/dag/ @crossplane/crossplane-reviewers @hasheddan -/internal/controller/pkg/ @crossplane/crossplane-reviewers @hasheddan +/apis/pkg/ @crossplane/crossplane-reviewers @turkenh +/internal/xpkg/ @crossplane/crossplane-reviewers @turkenh +/internal/dag/ @crossplane/crossplane-reviewers @turkenh +/internal/controller/pkg/ @crossplane/crossplane-reviewers @turkenh # Composition /apis/apiextensions/ @crossplane/crossplane-reviewers @muvaf @@ -53,6 +53,6 @@ # Misc /apis/secrets/ @crossplane/crossplane-reviewers @turkenh -/cmd/crank/ @crossplane/crossplane-reviewers @hasheddan +/cmd/crank/ @crossplane/crossplane-reviewers @negz /internal/initializer/ @crossplane/crossplane-reviewers @muvaf /internal/features/ @crossplane/crossplane-reviewers @negz From 0aee12a1966c639ed89dbb56ca61073c66361b40 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 19:51:33 +0000 Subject: [PATCH 139/148] Update module github.com/bufbuild/buf to v1.25.1 --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 583c16780..15afe65b7 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 - github.com/bufbuild/buf v1.25.0 + github.com/bufbuild/buf v1.25.1 github.com/crossplane/crossplane-runtime v0.20.0 github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 @@ -72,7 +72,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bufbuild/connect-go v1.9.0 // indirect github.com/bufbuild/connect-opentelemetry-go v0.4.0 // indirect - github.com/bufbuild/protocompile v0.5.1 // indirect + github.com/bufbuild/protocompile v0.6.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect @@ -155,7 +155,7 @@ require ( github.com/ryanuber/go-glob v1.0.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/tetratelabs/wazero v1.3.0 // indirect + github.com/tetratelabs/wazero v1.3.1 // indirect github.com/vbatts/tar-split v0.11.3 // indirect github.com/vladimirvivien/gexe v0.2.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect diff --git a/go.sum b/go.sum index 9182d3a79..5e2207096 100644 --- a/go.sum +++ b/go.sum @@ -123,14 +123,14 @@ github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bufbuild/buf v1.25.0 h1:HFxKrR8wFcZwrBInN50K/oJX/WOtPVq24rHb/ArjfBA= -github.com/bufbuild/buf v1.25.0/go.mod h1:GCKZ5bAP6Ht4MF7KcfaGVgBEXGumwAz2hXjjLVxx8ZU= +github.com/bufbuild/buf v1.25.1 h1:8ed5AjZ+zPIJf72rxtfsDit/MtaBimaSRn9Y+5G++y0= +github.com/bufbuild/buf v1.25.1/go.mod h1:UMPncXMWgrmIM+0QpwTEwjNr2SA0z2YIVZZsmNflvB4= github.com/bufbuild/connect-go v1.9.0 h1:JIgAeNuFpo+SUPfU19Yt5TcWlznsN5Bv10/gI/6Pjoc= github.com/bufbuild/connect-go v1.9.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= github.com/bufbuild/connect-opentelemetry-go v0.4.0 h1:6JAn10SNqlQ/URhvRNGrIlczKw1wEXknBUUtmWqOiak= github.com/bufbuild/connect-opentelemetry-go v0.4.0/go.mod h1:nwPXYoDOoc2DGyKE/6pT1Q9MPSi2Et2e6BieMD0l6WU= -github.com/bufbuild/protocompile v0.5.1 h1:mixz5lJX4Hiz4FpqFREJHIXLfaLBntfaJv1h+/jS+Qg= -github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40= +github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY= +github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= @@ -501,8 +501,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/tetratelabs/wazero v1.3.0 h1:nqw7zCldxE06B8zSZAY0ACrR9OH5QCcPwYmYlwtcwtE= -github.com/tetratelabs/wazero v1.3.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= +github.com/tetratelabs/wazero v1.3.1 h1:rnb9FgOEQRLLR8tgoD1mfjNjMhFeWRUk+a4b4j/GpUM= +github.com/tetratelabs/wazero v1.3.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= From 4aa947a1ab9895ba0e03809e5e7074309fb6bb9d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Aug 2023 01:04:26 +0000 Subject: [PATCH 140/148] Update module github.com/google/go-containerregistry to v0.16.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 15afe65b7..4793a6ef7 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/crossplane/crossplane-runtime v0.20.0 github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 - github.com/google/go-containerregistry v0.15.3-0.20230625233257-b8504803389b + github.com/google/go-containerregistry v0.16.1 github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230617045147-2472cbbbf289 github.com/google/uuid v1.3.0 github.com/jmattheis/goverter v0.17.4 diff --git a/go.sum b/go.sum index 5e2207096..62cb32302 100644 --- a/go.sum +++ b/go.sum @@ -293,8 +293,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.15.3-0.20230625233257-b8504803389b h1:nEV+eNboccNOCOkad/Zkx7nYG/xsk8cceS2Zew/VPzk= -github.com/google/go-containerregistry v0.15.3-0.20230625233257-b8504803389b/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= +github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230617045147-2472cbbbf289 h1:wk0QZFyD9RapJgFdQGb8+5+RtNxJsrVYpdEHfTc3Q8g= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20230617045147-2472cbbbf289/go.mod h1:Ek+8PQrShkA7aHEj3/zSW33wU0V/Bx3zW/gFh7l21xY= github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230516205744-dbecb1de8cfa h1:+MG+Q2Q7mtW6kCIbUPZ9ZMrj7xOWDKI1hhy1qp0ygI0= From 8a6264c305a0e98b37a5c4a10c789cc15caa9b1e Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 3 Aug 2023 09:26:56 +0200 Subject: [PATCH 141/148] chore: added docs reminder to PR checklist Signed-off-by: Philippe Scorsolini --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 67bce092b..48d3bb8fa 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,5 +27,6 @@ I have: - [ ] Added or updated unit **and** E2E tests for my change. - [ ] Run `make reviewable` to ensure this PR is ready for review. - [ ] Added `backport release-x.y` labels to auto-backport this PR if necessary. +- [ ] Opened a PR updating the [docs](https://docs.crossplane.io/contribute/contribute/), if necessary. -[contribution process]: https://git.io/fj2m9 \ No newline at end of file +[contribution process]: https://git.io/fj2m9 From 47f58868df9b0e1dbaccf10f6e55ae8567cbb77c Mon Sep 17 00:00:00 2001 From: Christopher Haar Date: Fri, 4 Aug 2023 11:48:43 +0200 Subject: [PATCH 142/148] fix(crds): add crd migration for locks.pkg.crossplane.io v1alpha1 Signed-off-by: Christopher Haar --- cmd/crossplane/core/init.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/crossplane/core/init.go b/cmd/crossplane/core/init.go index fcc285f58..d6be87f8c 100644 --- a/cmd/crossplane/core/init.go +++ b/cmd/crossplane/core/init.go @@ -71,11 +71,13 @@ func (c *initCommand) Run(s *runtime.Scheme, log logging.Logger) error { initializer.NewWebhookCertificateGenerator(nn, c.Namespace, log.WithValues("Step", "WebhookCertificateGenerator")), initializer.NewCoreCRDsMigrator("compositionrevisions.apiextensions.crossplane.io", "v1alpha1"), + initializer.NewCoreCRDsMigrator("locks.pkg.crossplane.io", "v1alpha1"), initializer.NewCoreCRDs("/crds", s, initializer.WithWebhookTLSSecretRef(nn)), initializer.NewWebhookConfigurations("/webhookconfigurations", s, nn, svc)) } else { steps = append(steps, initializer.NewCoreCRDsMigrator("compositionrevisions.apiextensions.crossplane.io", "v1alpha1"), + initializer.NewCoreCRDsMigrator("locks.pkg.crossplane.io", "v1alpha1"), initializer.NewCoreCRDs("/crds", s), ) } From f0b37681b709031d6623abfc47668213936c2b02 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Thu, 27 Jul 2023 12:00:32 +0200 Subject: [PATCH 143/148] fix: avoid panics due to reflect.TypeOf usage Signed-off-by: Philippe Scorsolini --- .../composite/composition_transforms.go | 16 ++++------------ .../composite/environment/selector.go | 5 ++++- internal/initializer/initializer.go | 16 +++++++++++++++- internal/initializer/webhook_configurations.go | 3 +-- test/e2e/funcs/feature.go | 10 +++++++++- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/internal/controller/apiextensions/composite/composition_transforms.go b/internal/controller/apiextensions/composite/composition_transforms.go index 48f6c2651..66c66f71c 100644 --- a/internal/controller/apiextensions/composite/composition_transforms.go +++ b/internal/controller/apiextensions/composite/composition_transforms.go @@ -24,7 +24,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "reflect" "regexp" "strconv" "strings" @@ -194,14 +193,7 @@ func ResolveMap(t v1.MapTransform, input any) (any, error) { } return val, nil default: - var inputType string - if input == nil { - inputType = "nil" - } else { - inputType = reflect.TypeOf(input).String() - } - - return nil, errors.Errorf(errFmtMapTypeNotSupported, inputType) + return nil, errors.Errorf(errFmtMapTypeNotSupported, fmt.Sprintf("%T", input)) } } @@ -254,7 +246,7 @@ func matchesLiteral(p v1.MatchTransformPattern, input any) (bool, error) { } inputStr, ok := input.(string) if !ok { - return false, errors.Errorf(errFmtMatchInputTypeInvalid, reflect.TypeOf(input).String()) + return false, errors.Errorf(errFmtMatchInputTypeInvalid, fmt.Sprintf("%T", input)) } return inputStr == *p.Literal, nil } @@ -272,7 +264,7 @@ func matchesRegexp(p v1.MatchTransformPattern, input any) (bool, error) { } inputStr, ok := input.(string) if !ok { - return false, errors.Errorf(errFmtMatchInputTypeInvalid, reflect.TypeOf(input).String()) + return false, errors.Errorf(errFmtMatchInputTypeInvalid, fmt.Sprintf("%T", input)) } return re.MatchString(inputStr), nil } @@ -387,7 +379,7 @@ func ResolveConvert(t v1.ConvertTransform, input any) (any, error) { return nil, err } - from := v1.TransformIOType(reflect.TypeOf(input).String()) + from := v1.TransformIOType(fmt.Sprintf("%T", input)) if !from.IsValid() { return nil, errors.Errorf(errFmtConvertInputTypeNotSupported, input) } diff --git a/internal/controller/apiextensions/composite/environment/selector.go b/internal/controller/apiextensions/composite/environment/selector.go index e07feb997..b78bb8f3c 100644 --- a/internal/controller/apiextensions/composite/environment/selector.go +++ b/internal/controller/apiextensions/composite/environment/selector.go @@ -191,7 +191,10 @@ func sortConfigs(ec []v1alpha1.EnvironmentConfig, f string) error { //nolint:goc return err } - vt := reflect.TypeOf(val).Kind() + var vt reflect.Kind + if val != nil { + vt = reflect.TypeOf(val).Kind() + } // check only vt1 as vt1 == vt2 switch vt { //nolint:exhaustive // we only support these types diff --git a/internal/initializer/initializer.go b/internal/initializer/initializer.go index 1eb033c64..c2fab199e 100644 --- a/internal/initializer/initializer.go +++ b/internal/initializer/initializer.go @@ -19,6 +19,7 @@ package initializer import ( "context" + "fmt" "reflect" "sigs.k8s.io/controller-runtime/pkg/client" @@ -47,10 +48,23 @@ type Initializer struct { // Init does all operations necessary for controllers and webhooks to work. func (c *Initializer) Init(ctx context.Context) error { for _, s := range c.steps { + if s == nil { + continue + } if err := s.Run(ctx, c.kube); err != nil { return err } - c.log.Info("Step has been completed", "Name", reflect.TypeOf(s).Elem().Name()) + t := reflect.TypeOf(s) + var name string + if t != nil { + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + name = t.Name() + } else { + name = fmt.Sprintf("%T", s) + } + c.log.Info("Step has been completed", "Name", name) } return nil } diff --git a/internal/initializer/webhook_configurations.go b/internal/initializer/webhook_configurations.go index 52d6be461..ad69aa3fc 100644 --- a/internal/initializer/webhook_configurations.go +++ b/internal/initializer/webhook_configurations.go @@ -18,7 +18,6 @@ package initializer import ( "context" - "reflect" "github.com/spf13/afero" admv1 "k8s.io/api/admissionregistration/v1" @@ -124,7 +123,7 @@ func (c *WebhookConfigurations) Run(ctx context.Context, kube client.Client) err // See https://github.com/kubernetes-sigs/controller-tools/issues/658 conf.SetName("crossplane") default: - return errors.Errorf("only MutatingWebhookConfiguration and ValidatingWebhookConfiguration kinds are accepted, got %s", reflect.TypeOf(obj).String()) + return errors.Errorf("only MutatingWebhookConfiguration and ValidatingWebhookConfiguration kinds are accepted, got %T", obj) } if err := pa.Apply(ctx, obj.(client.Object)); err != nil { return errors.Wrap(err, errApplyWebhookConfiguration) diff --git a/test/e2e/funcs/feature.go b/test/e2e/funcs/feature.go index 3f5310e14..4e78f2d4e 100644 --- a/test/e2e/funcs/feature.go +++ b/test/e2e/funcs/feature.go @@ -518,7 +518,15 @@ func asUnstructured(o runtime.Object) *unstructured.Unstructured { func identifier(o k8s.Object) string { k := o.GetObjectKind().GroupVersionKind().Kind if k == "" { - k = reflect.TypeOf(o).Elem().Name() + t := reflect.TypeOf(o) + if t != nil { + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + k = t.Name() + } else { + k = fmt.Sprintf("%T", o) + } } if o.GetNamespace() == "" { return fmt.Sprintf("%s %s", k, o.GetName()) From 321c41ddd21c92a46bdb49d6e1d52af0e8771176 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Aug 2023 19:27:06 +0000 Subject: [PATCH 144/148] Update module golang.org/x/sys to v0.11.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4793a6ef7..b72cbec35 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.10.0 + golang.org/x/sys v0.11.0 google.golang.org/grpc v1.57.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/protobuf v1.31.0 diff --git a/go.sum b/go.sum index 62cb32302..e3d4e5e24 100644 --- a/go.sum +++ b/go.sum @@ -717,8 +717,8 @@ golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= From 8bcf05db8770ee09fa65bc9becd30acf2cbc5de2 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Mon, 7 Aug 2023 12:56:43 +0200 Subject: [PATCH 145/148] docs: add further details to release issue template Signed-off-by: Philippe Scorsolini --- .github/ISSUE_TEMPLATE/patch_release.md | 2 +- .github/ISSUE_TEMPLATE/release.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/patch_release.md b/.github/ISSUE_TEMPLATE/patch_release.md index 3bc5f0552..ccc19617b 100644 --- a/.github/ISSUE_TEMPLATE/patch_release.md +++ b/.github/ISSUE_TEMPLATE/patch_release.md @@ -29,7 +29,7 @@ examples of each step, assuming vX.Y.Z is being cut. - [ ] `xp/getting-started-with-azure` - [ ] `xp/getting-started-with-gcp` - [ ] Run the [Promote workflow][promote-workflow] with channel `stable` on the `release-X.Y` branch and verified that the tagged build version exists on the [releases.crossplane.io] `stable` channel at `stable/vX.Y.Z/...`. -- [ ] Published a [new release] for the tagged version, with the same name as the version and descriptive release notes, taking care of generating the changes list selecting as "Previous tag" `vX.Y.`, so the previous patch release for the same minor. +- [ ] Published a [new release] for the tagged version, with the same name as the version and descriptive release notes, taking care of generating the changes list selecting as "Previous tag" `vX.Y.`, so the previous patch release for the same minor. Before publishing the release notes, set them as Draft and ask the rest of the team to double check them. - [ ] Ensured that users have been notified of the release on all communication channels: - [ ] Slack: `#announcements` channel on Crossplane's Slack workspace. - [ ] Twitter: reach out to a Crossplane maintainer or steering committee member, see [OWNERS.md][owners]. diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 679118093..5f786ce0e 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -22,7 +22,7 @@ this issue for posterity. Refer to this [prior release issue][release-1.11.0] fo examples of each step, assuming release vX.Y.0 is being cut. - [ ] Prepared the release branch `release-X.Y` at the beginning of [Code Freeze]: - - [ ] Created the release branch. + - [ ] Created the release branch using the [GitHub UI][create-branch]. - [ ] Created and merged an empty commit to the `master` branch, if required to have it at least one commit ahead of the release branch. - [ ] Run the [Tag workflow][tag-workflow] on the `master` branch with the release candidate tag for the next release `vX.Y+1.0-rc.0`. - [ ] Opened a [docs release issue]. @@ -34,7 +34,7 @@ examples of each step, assuming release vX.Y.0 is being cut. - [ ] `xp/getting-started-with-azure` - [ ] `xp/getting-started-with-gcp` - [ ] Run the [Promote workflow][promote-workflow] with channel `stable` on the `release-X.Y` branch and verified that the tagged build version exists on the [releases.crossplane.io] `stable` channel at `stable/vX.Y.0/...`. -- [ ] Published a [new release] for the tagged version, with the same name as the version and descriptive release notes, taking care of generating the changes list selecting as "Previous tag" `vX..0`, so the first of the releases for the previous minor. +- [ ] Published a [new release] for the tagged version, with the same name as the version and descriptive release notes, taking care of generating the changes list selecting as "Previous tag" `vX..0`, so the first of the releases for the previous minor. Before publishing the release notes, set them as Draft and ask the rest of the team to double check them. - [ ] Checked that the [docs release issue] created previously has been completed. - [ ] Updated, in a single PR, the following on `master`: - [ ] The [releases table] in the `README.md`, removing the now old unsupported release and adding the new one. @@ -49,6 +49,7 @@ examples of each step, assuming release vX.Y.0 is being cut. [Code Freeze]: https://docs.crossplane.io/knowledge-base/guides/release-cycle/#code-freeze [ci-workflow]: https://github.com/crossplane/crossplane/actions/workflows/ci.yml [configurations-workflow]: https://github.com/crossplane/crossplane/actions/workflows/configurations.yml +[create-branch]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-and-deleting-branches-within-your-repository [docs release issue]: https://github.com/crossplane/docs/issues/new?assignees=&labels=release&template=new_release.md&title=Release+Crossplane+version...+ [new release]: https://github.com/crossplane/crossplane/releases/new [owners]: https://github.com/crossplane/crossplane/blob/master/OWNERS.md From 607a72b5b216e2b6312bc605727de373aa9c7422 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:13:48 +0000 Subject: [PATCH 146/148] Update module github.com/crossplane/crossplane-runtime to v0.20.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b72cbec35..0c090247e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver v1.5.0 github.com/alecthomas/kong v0.8.0 github.com/bufbuild/buf v1.25.1 - github.com/crossplane/crossplane-runtime v0.20.0 + github.com/crossplane/crossplane-runtime v0.20.1 github.com/cyphar/filepath-securejoin v0.2.3 github.com/google/go-cmp v0.5.9 github.com/google/go-containerregistry v0.16.1 diff --git a/go.sum b/go.sum index e3d4e5e24..a4c2be094 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/crossplane/crossplane-runtime v0.20.0 h1:MlPNrK6ELKLQdeHaIdKxQpZW2LSivSYXxHKVfU32auU= -github.com/crossplane/crossplane-runtime v0.20.0/go.mod h1:FuKIC8Mg8hE2gIAMyf2wCPkxkFPz+VnMQiYWBq1/p5A= +github.com/crossplane/crossplane-runtime v0.20.1 h1:xEYNL65wq3IA4NloSknH/n7F/GVKQd3QDpNWB4dFRks= +github.com/crossplane/crossplane-runtime v0.20.1/go.mod h1:FuKIC8Mg8hE2gIAMyf2wCPkxkFPz+VnMQiYWBq1/p5A= github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= From 15c83cb4ea073648d2382e8bdda7a808be3a6727 Mon Sep 17 00:00:00 2001 From: Philippe Scorsolini Date: Mon, 7 Aug 2023 14:52:03 +0200 Subject: [PATCH 147/148] chore(renovate): enable conventional commits Signed-off-by: Philippe Scorsolini --- .github/renovate.json5 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 0025c9c95..dcef14d35 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -2,7 +2,8 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base", - "helpers:pinGitHubActionDigests" + "helpers:pinGitHubActionDigests", + ":semanticCommits" ], // We only want renovate to rebase PRs when they have conflicts, // default "auto" mode is not required. @@ -14,9 +15,6 @@ "baseBranches": ["master","release-1.11","release-1.12","release-1.13"], "ignorePaths": ["design/**"], "postUpdateOptions": ["gomodTidy"], -// By default renovate will auto detect whether semantic commits have been used -// in the recent history and comply with that, we explicitly disable it - "semanticCommits": "disabled", // All PRs should have a label "labels": ["automated"], "regexManagers": [ From 1ffb22cec7a9881a62abd0bd8c9d3fc2f35923ba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:43:01 +0000 Subject: [PATCH 148/148] chore(deps): update module golang.org/x/net to v0.13.0 [security] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0c090247e..16c9799a7 100644 --- a/go.mod +++ b/go.mod @@ -167,7 +167,7 @@ require ( go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.11.0 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect; indirect // indirect + golang.org/x/net v0.13.0 // indirect; indirect // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect diff --git a/go.sum b/go.sum index a4c2be094..ff32c864e 100644 --- a/go.sum +++ b/go.sum @@ -634,8 +634,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=