Compare commits

...

906 Commits

Author SHA1 Message Date
Hasan Turken 1e3dba95ee
Merge pull request #854 from erhancagirici/ec-xpv2
add v2 apis
2025-07-22 17:33:02 +03:00
Erhan Cagirici cf256f8643 use correct namespace from MR in MultiNamespacedResolution
Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-22 16:59:23 +03:00
Erhan Cagirici 14718766b2 make generate: protobuf updates after protoc-gen-go-grpc bump
Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-22 13:16:29 +03:00
Erhan Cagirici 8ba120d73e make generate: refactored common api deepcopy methods
Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-22 13:15:24 +03:00
Erhan Cagirici 5c98d3248a bump controller-tools to v1.18.0
fixes deepcopy method generation for structs that has aliased types

Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-22 13:12:11 +03:00
Erhan Cagirici c056ae9de1 refactor shared api types to common package
Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-22 13:12:01 +03:00
Erhan Cagirici 54f050c217 add unit tests for v2
Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-21 18:26:28 +03:00
Erhan Cagirici f09b0a3b35 add v2 apis
Signed-off-by: Erhan Cagirici <erhan@upbound.io>
2025-07-21 18:25:20 +03:00
Nic Cope ab24452c43
Merge pull request #829 from orange-cloudfoundry/feature-namespace-restricted-option
Add filter functions to event recorder
2025-07-18 18:40:28 -07:00
Nic Cope f5f608c93d
Merge pull request #856 from n3wscott/gate-until
Adding Gate and a CustomResourceGate reconciler
2025-07-11 15:08:17 -07:00
Scott Nichols 990e45c003 check for nil gates in setup, not reconcile.
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-07-10 18:01:26 -07:00
Scott Nichols 066eac1759 use satisfied to make them bools
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-07-10 17:57:42 -07:00
Scott Nichols 68a06acc30 nit on underscores
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-07-10 17:55:55 -07:00
Scott Nichols d8f858d664 react to feedback, make the interface tighter on the gate
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-07-10 17:54:21 -07:00
Scott Nichols 8cc1013bff Adding Gate implementation and a reconciler that reconciles and tracks CRDs to use and unlock the gates registered
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-07-10 14:57:24 -07:00
Philippe Scorsolini 3029c4a90a
Merge pull request #852 from negz/y-u-do-this-golangci
Bump to Go v1.24, and golangci-lint v2.2.0
2025-07-04 16:42:44 +02:00
Nic Cope 678177c524 Run golangci-lint run --fix
This commit is entirely generated by earthly +reviewable

Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-07-03 12:51:13 -07:00
Nic Cope aad05b013a Address false positive recvcheck linter warning
Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-07-03 12:49:57 -07:00
Nic Cope a592ede87e Address linter warnings about embedded structs
Specifically it wants them to appear first, before non-embedded things.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-07-03 11:34:05 -07:00
Nic Cope d65515ca89 Bump Go to v1.24, golangci-lint to v2.2
Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-07-03 11:33:30 -07:00
Nic Cope ebceaacf21 Drop c/c import rule
We don't import c/c here

Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-07-03 11:28:02 -07:00
Nic Cope a2ee2dddbd Copy v2 golangci config from c/c
Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-07-03 11:27:14 -07:00
Nic Cope 0d81d3f7c2
Merge pull request #849 from negz/x-treme
Backport c/c internal/xresource
2025-06-20 11:57:48 -07:00
Nic Cope 794eae126b Backport c/c internal/xresource
Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-06-17 17:27:55 -07:00
François Rigaut 61bc9edaf2 add filter functions to event recorder
Signed-off-by: François Rigaut <francois.rigaut@orange.com>
2025-06-11 14:21:25 +02:00
Nic Cope 2b288ff362
Merge pull request #841 from nolancon/requeue-deterministic-mr-if-pending
Avoid non-requeue for MRs with determinstic external names.
2025-06-09 13:19:44 -07:00
Jared Watts 0063d2988c
Merge pull request #843 from jbw976/v2-providers
feat: enable namespaced reference resolution
2025-06-09 12:05:46 +02:00
Jared Watts dd27392560
feat: enable namespaced reference resolution
Signed-off-by: Jared Watts <jbw976@gmail.com>
2025-06-09 11:48:38 +02:00
Jared Watts 28c1851bf5
Merge pull request #802 from guilhem/ResolveMultipleOrder
fix: order values in MultiResolutionResponse
2025-06-09 11:16:26 +02:00
nolancon 6120cd37b6 Add debug log for pending + deterministic name case
Signed-off-by: nolancon <cmsnolan@gmail.com>
2025-06-09 08:33:12 +00:00
Jared Watts 27a394364d
Merge pull request #846 from negz/dirty-dirty-repo
Run `go mod tidy`
2025-06-07 17:32:31 +02:00
Guilhem Lettron d48e582450 fix: order values in MultiResolutionResponse
Signed-off-by: Guilhem Lettron <glettron@akamai.com>
2025-06-07 16:31:32 +02:00
Nic Cope fcbcd1a315 Run go mod tidy
Signed-off-by: Nic Cope <nicc@rk0n.org>
2025-06-06 21:41:09 -07:00
Nic Cope 43879203d3
Merge pull request #826 from johngmyers/cobra
chore(deps): update module github.com/spf13/cobra to v1.9.1
2025-06-06 21:30:02 -07:00
Nic Cope 27adbc5d9e
Merge pull request #816 from crossplane/renovate/main-renovatebot-github-action-40.x
chore(deps): update renovatebot/github-action action to v40.3.6 (main)
2025-06-06 21:24:55 -07:00
Nic Cope e41983dddc
Merge pull request #817 from crossplane/renovate/main-github.com-google-go-cmp-0.x
fix(deps): update module github.com/google/go-cmp to v0.7.0 (main)
2025-06-06 21:23:27 -07:00
Nic Cope 739f7236b8
Merge pull request #814 from crossplane/renovate/main-actions-create-github-app-token-digest
chore(deps): update actions/create-github-app-token digest to d72941d (main)
2025-06-06 21:12:57 -07:00
nolancon da72350d65 Add deterministicExternalName to ReconcilerOptions
Signed-off-by: nolancon <cmsnolan@gmail.com>
2025-06-06 11:38:47 +00:00
nolancon 334eed1791 Revert "Add AnnotationKeyExternalNameIsDeterministic with helper"
This reverts commit fb7b837275.

Signed-off-by: nolancon <cmsnolan@gmail.com>
2025-06-06 11:37:38 +00:00
nolancon 386b31235c Revert "Only avoid re-queue for non-deterministically named resources"
This reverts commit 604c58f9eb.

Signed-off-by: nolancon <cmsnolan@gmail.com>
2025-06-06 11:37:13 +00:00
nolancon 604c58f9eb Only avoid re-queue for non-deterministically named resources
Signed-off-by: nolancon <cmsnolan@gmail.com>
2025-05-28 10:13:52 +00:00
nolancon fb7b837275 Add AnnotationKeyExternalNameIsDeterministic with helper
Signed-off-by: nolancon <cmsnolan@gmail.com>
2025-05-28 10:13:52 +00:00
Nic Cope 532a1c432f
Merge pull request #838 from chlunde/unfmt
Update Event recorder to not parse % format characters in error message
2025-05-21 14:26:55 -07:00
Nic Cope 15b6a5540c
Merge pull request #840 from n3wscott/fix-dupe-interface
fix lint issue on deprecated interfaces
2025-05-21 14:26:22 -07:00
Scott Nichols fa083bc2b6 fix lint issue on deprecated interfaces
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-21 14:08:14 -07:00
Jared Watts 0002011004
Merge pull request #839 from jbw976/base-branch-bump
build: remove release-1.17 from renovate baseBranches
2025-05-21 11:47:18 +01:00
Jared Watts c3c1a2262b
build: remove release-1.17 from renovate baseBranches
Signed-off-by: Jared Watts <jbw976@gmail.com>
2025-05-21 11:38:53 +01:00
Nic Cope 0812f329d5
Merge pull request #835 from n3wscott/fix-connector
Correct Connector and Disconnector typos, add aliases to prevent breakage.
2025-05-19 16:17:03 -07:00
Carl Henrik Lunde 3178304167 Update Event recorder to not parse % format characters in error message
*Eventf takes a format string. This change passes "%s" as the format string
and then the unsanitized string as an argument.

Fixes #837

Signed-off-by: Carl Henrik Lunde <chlunde@ifi.uio.no>
2025-05-19 20:43:35 +02:00
Jared Watts 54effc73f9
Merge pull request #836 from jbw976/base-branch-bump
chore: add release-1.20 to renovate baseBranches
2025-05-13 19:47:19 +01:00
Jared Watts dd5c50cbf1
chore: add release-1.20 to renovate baseBranches
Signed-off-by: Jared Watts <jbw976@gmail.com>
2025-05-13 19:15:12 +01:00
Jared Watts e4095cafe1
Merge pull request #822 from crossplane/renovate/main-go-golang.org-x-net-vulnerability
chore(deps): update module golang.org/x/net to v0.38.0 [security] (main)
2025-05-13 19:08:33 +01:00
crossplane-renovate[bot] c43328fcce
chore(deps): update module golang.org/x/net to v0.38.0 [security] 2025-05-13 17:57:06 +00:00
Jared Watts e68a2c6d18
Merge pull request #818 from crossplane/renovate/main-go-golang.org-x-oauth2-vulnerability
chore(deps): update module golang.org/x/oauth2 to v0.27.0 [security] (main)
2025-05-13 18:53:03 +01:00
Jared Watts 8e6ab168b4
chore(lint): bump go/golangci-lint versions and fix all linter errors
This commit bumps the golang version to the same used currently in
core crossplane (1.23.7) and then uses the latest 1.x version of
golangci-lint. Previous versions of golangci-lint are tough to use
because of recvcheck not supporting exclusions until its v0.2.0 release.

This commit shares some similar fixes as seen in https://github.com/crossplane/crossplane/pull/6111

Signed-off-by: Jared Watts <jbw976@gmail.com>
2025-05-13 18:22:15 +01:00
Scott Nichols bbe80d8327 Move func alias from var to func wrapper.
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-13 08:59:35 -07:00
Scott Nichols 6ac64baa77 Correct Connector and Disconnector typos, add aliases to prevent breakage.
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-12 16:15:45 -07:00
Nic Cope 1a8b6a8ea2
Merge pull request #828 from n3wscott/managed-og
Update Managed reconciler to store observedGeneration in conditions
2025-05-09 11:20:16 -07:00
Scott Nichols 8bd28819a2 fix two missed locations of migrating from WithOG to Mark
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-09 11:02:12 -07:00
Scott Nichols 8b73d977b4 rebase
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-09 10:58:39 -07:00
Scott Nichols 90bd25085e Update to use the new condtions manager for observedGeneration
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-09 10:58:39 -07:00
Scott Nichols 6beb360454 Update managed reconciler to store observedGeneration on conditions and also update that controllers unit tests
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-09 10:58:39 -07:00
Jared Watts 26da25aff6
Merge pull request #833 from sergenyalcin/revert-780-chore-deprecate-pointer-helper-function
Revert "chore: deprecate the reference pointer helper functions"
2025-05-09 12:31:21 +01:00
Sergen Yalçın 79b8fcfb38
Revert "chore: deprecate the reference pointer helper functions"
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2025-05-09 11:08:35 +03:00
Nic Cope 47f1c0a3c3
Merge pull request #831 from n3wscott/manager
Introduce a conditions manager.
2025-05-05 15:41:37 -07:00
Scott Nichols 22869d9be7 update names and method names to match project
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-05 14:28:31 -07:00
Scott Nichols b21e95ebcd Update based on feedback
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-02 15:54:26 -07:00
Scott Nichols 8c883197a9 Introduce a condtions package with a light weight manager to help enable coordinated condition updates
Signed-off-by: Scott Nichols <n3wscott@upbound.io>
2025-05-02 11:46:16 -07:00
John Gardiner Myers 0c53fc3e34 chore(deps): update module github.com/spf13/cobra to v1.9.1
Removes one reason the linker can't do dead-code elimination

Signed-off-by: John Gardiner Myers <jgmyers@proofpoint.com>
2025-03-29 10:34:44 -07:00
crossplane-renovate[bot] daf7264750
chore(deps): update actions/create-github-app-token digest to d72941d 2025-03-28 08:05:10 +00:00
crossplane-renovate[bot] 2ec9a898fc
chore(deps): update module golang.org/x/oauth2 to v0.27.0 [security] 2025-03-05 08:05:19 +00:00
crossplane-renovate[bot] 521fee3cbb
fix(deps): update module github.com/google/go-cmp to v0.7.0 2025-03-02 08:05:46 +00:00
crossplane-renovate[bot] a123ea42e5
chore(deps): update renovatebot/github-action action to v40.3.6 2025-03-02 08:04:20 +00:00
Bob Haddleton db9545b7a2
Merge pull request #812 from crossplane/renovate/main-github-codeql-action-2.x
chore(deps): update dependency github/codeql-action to v2.20.5 (main)
2025-02-28 09:37:26 +01:00
Bob Haddleton fed95717b2
Merge pull request #811 from crossplane/renovate/main-github-codeql-action-digest
chore(deps): update github/codeql-action digest to b56ba49 (main)
2025-02-28 09:36:58 +01:00
Bob Haddleton f16137f33a
Merge pull request #810 from crossplane/renovate/main-aquasecurity-trivy-action-0.x
chore(deps): update aquasecurity/trivy-action action to v0.29.0 (main)
2025-02-28 09:36:30 +01:00
Bob Haddleton f9de1356b9
Merge pull request #809 from crossplane/renovate/main-github.com-evanphx-json-patch-5.x
fix(deps): update module github.com/evanphx/json-patch to v5.9.11+incompatible (main)
2025-02-28 09:36:06 +01:00
Hasan Turken 5faceb9d8a
Merge pull request #788 from man-ish-k/feat-additional-management-policy-combination
feat: support additional management policy combination
2025-02-25 11:41:37 +03:00
crossplane-renovate[bot] e68796f9fc
chore(deps): update github/codeql-action digest to b56ba49 2025-02-22 08:04:04 +00:00
crossplane-renovate[bot] 3676c4725d
chore(deps): update dependency github/codeql-action to v2.20.5 2025-02-21 08:05:18 +00:00
Manish Kumar 780e99f8fc Remove duplicate test cases
Signed-off-by: Manish Kumar <mk14445@gmail.com>
2025-02-12 22:05:30 +05:30
Jared Watts 10d8643c29
Merge pull request #813 from markandersontrocme/update-renovate-1-19
chore: remove crossplane 1.16
2025-02-11 07:23:53 -08:00
Mark Anderson-Trocme bb9478e409
chore: remove crossplane 1.16
Signed-off-by: Mark Anderson-Trocme <mark.andersontrocme@upbound.io>
2025-02-11 10:18:09 -05:00
crossplane-renovate[bot] 3ae59110ca
chore(deps): update aquasecurity/trivy-action action to v0.29.0 2025-02-07 08:05:57 +00:00
crossplane-renovate[bot] 79cb790407
fix(deps): update module github.com/evanphx/json-patch to v5.9.11+incompatible 2025-02-07 08:05:52 +00:00
Bob Haddleton 4ac6fb5c7c
Merge pull request #785 from crossplane/renovate/main-actions-checkout-4.x
chore(deps): update actions/checkout action to v4.2.2 (main)
2025-02-06 08:46:28 -06:00
Bob Haddleton d9bba969fc
Merge pull request #807 from crossplane/renovate/main-actions-create-github-app-token-digest
chore(deps): update actions/create-github-app-token digest to 67e27a7 (main)
2025-02-06 08:45:58 -06:00
Bob Haddleton b00d456004
Merge pull request #808 from crossplane/renovate/main-actions-stale-digest
chore(deps): update actions/stale digest to 5bef64f (main)
2025-02-06 08:45:30 -06:00
crossplane-renovate[bot] 13f79f60f2
chore(deps): update actions/checkout action to v4.2.2 2025-02-06 08:04:59 +00:00
crossplane-renovate[bot] 6f92714901
chore(deps): update actions/stale digest to 5bef64f 2025-02-06 08:04:54 +00:00
crossplane-renovate[bot] 4cee0c2263
chore(deps): update actions/create-github-app-token digest to 67e27a7 2025-02-06 08:04:48 +00:00
Bob Haddleton 33fc8cae7e
Merge pull request #784 from crossplane/renovate/main-github-codeql-action-digest
chore(deps): update github/codeql-action digest to dd74661 (main)
2025-02-05 12:46:06 -06:00
Bob Haddleton 4979979385
Merge pull request #783 from crossplane/renovate/main-codecov-codecov-action-digest
chore(deps): update codecov/codecov-action digest to b9fd7d1 (main)
2025-02-05 12:45:33 -06:00
Bob Haddleton 139fa84c49
Merge pull request #782 from crossplane/renovate/main-actions-checkout-digest
chore(deps): update actions/checkout digest to 11bd719 (main)
2025-02-05 12:44:59 -06:00
Jared Watts 00daaa33b4
Merge pull request #806 from markandersontrocme/setup-release-1-19
add release-1.19 to baseBranches
2025-02-04 10:26:52 -08:00
Mark Anderson-Trocme a917463cdd
add release-1.19 to baseBranches
Signed-off-by: Mark Anderson-Trocme <mark.andersontrocme@upbound.io>
2025-02-04 13:23:56 -05:00
crossplane-renovate[bot] cd5c55e07f
chore(deps): update github/codeql-action digest to dd74661 2025-01-30 08:04:49 +00:00
Jared Watts 0eae57e9c0
Merge pull request #800 from jbw976/renovate-commands
chore: Renovate should run earthly commands for newer release branches
2024-12-22 06:16:04 -08:00
Jared Watts 8273d6461c
chore: Renovate should run earthly commands for newer release branches
Signed-off-by: Jared Watts <jbw976@gmail.com>
2024-12-19 19:15:34 -08:00
Jared Watts 197fb2a4a5
Merge pull request #793 from crossplane/renovate/main-go-golang.org-x-net-vulnerability
chore(deps): update module golang.org/x/net to v0.33.0 [security] (main)
2024-12-19 17:34:03 -08:00
Jared Watts 2c30d2977a
Merge pull request #797 from jbw976/fix-renovate-config
chore: bump renovate base branches
2024-12-19 14:36:46 -08:00
Jared Watts 652977a767
chore: bump renovate base branches
Signed-off-by: Jared Watts <jbw976@gmail.com>
2024-12-19 09:24:52 -08:00
crossplane-renovate[bot] 0b3aa5e61e
chore(deps): update module golang.org/x/net to v0.33.0 [security] 2024-12-19 08:05:57 +00:00
crossplane-renovate[bot] c0073578d4
chore(deps): update codecov/codecov-action digest to b9fd7d1 2024-12-17 08:06:08 +00:00
Manish Kumar 32db6df6b1 feat: support additional management policy combination
Signed-off-by: Manish Kumar <mk14445@gmail.com>
2024-11-10 14:08:46 +05:30
Hasan Turken 19d95a69cc
Merge pull request #786 from turkenh/fix-unknown-fields
Fix unknown fields warnings and possibility to suppress finalizer ones
2024-11-05 10:14:56 +03:00
Nic Cope e66c7ab42f
Merge pull request #780 from cychiang/chore-deprecate-pointer-helper-function
chore: deprecate the reference pointer helper functions
2024-11-04 12:04:27 -08:00
Hasan Turken 70499a4edd
CompositionRevisionRefence only has Name, so LocalObjectReference
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2024-11-04 22:23:50 +03:00
Hasan Turken 99dd2c0b51
Add reference type for composite
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2024-11-04 13:01:09 +03:00
crossplane-renovate[bot] 8885cff3c4
chore(deps): update actions/checkout digest to 11bd719 2024-11-01 08:04:38 +00:00
Hasan Turken 33515178ea
Merge pull request #781 from turkenh/empty-after-release-1.18
Empty commit after release-1.18
2024-10-31 16:14:23 +03:00
Hasan Turken 1e4e83e377
Empty commit after release-1.18
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2024-10-31 16:12:16 +03:00
Hasan Turken 097d1c72eb
Merge pull request #775 from crossplane/renovate/main-github-codeql-action-2.x
chore(deps): update dependency github/codeql-action to v2.19.2 (main)
2024-10-31 16:04:55 +03:00
Hasan Turken b23abe1e51
Merge pull request #774 from crossplane/renovate/main-aquasecurity-trivy-action-0.x
chore(deps): update aquasecurity/trivy-action action to v0.28.0 (main)
2024-10-31 16:04:31 +03:00
Hasan Turken a580ca10a3
Merge pull request #768 from crossplane/renovate/main-docker-login-action-digest
chore(deps): update docker/login-action digest to 9780b0c (main)
2024-10-31 16:01:31 +03:00
Hasan Turken a3fd556c5d
Merge pull request #767 from crossplane/renovate/main-actions-create-github-app-token-digest
chore(deps): update actions/create-github-app-token digest to 5d869da (main)
2024-10-31 16:01:09 +03:00
Chuan-Yen Chiang 5cb43a5a26 The change is done by earthly +reviewable
Signed-off-by: Chuan-Yen Chiang <cychiang0823@gmail.com>
2024-10-30 18:40:04 +01:00
Chuan-Yen Chiang e50f3cffc8 Merge branch 'main' into chore-deprecate-pointer-helper-function
Signed-off-by: Chuan-Yen Chiang <cychiang0823@gmail.com>
2024-10-30 18:24:58 +01:00
Philippe Scorsolini e6bea2f005
Merge pull request #761 from MisterMX/feat/typed-external-connector
feat(managed): Add generic interfaces for external types
2024-10-24 11:41:52 +01:00
crossplane-renovate[bot] 86d1b0e2ba
chore(deps): update dependency github/codeql-action to v2.19.2 2024-10-22 08:04:44 +00:00
crossplane-renovate[bot] 3bb290b23e
chore(deps): update aquasecurity/trivy-action action to v0.28.0 2024-10-16 08:04:40 +00:00
Chuan-Yen Chiang 3cdde89278 resolves crossplane/crossplane-runtime#762
Signed-off-by: Chuan-Yen Chiang <cychiang0823@gmail.com>
2024-10-04 22:35:39 +02:00
Nic Cope 08da772940
Merge pull request #760 from MisterMX/feat/controller-runtime-v0.19.0
feat: Upgrade controller-runtime to v0.19.0
2024-09-17 11:53:19 -07:00
Nic Cope ff72c15b02
Merge pull request #770 from crossplane/renovate/main-actions-checkout-4.x
chore(deps): update actions/checkout action to v4.1.7 (main)
2024-09-17 11:50:15 -07:00
Nic Cope 2a792f5f0b
Merge pull request #771 from crossplane/renovate/main-earthly-earthly-0.x
chore(deps): update dependency earthly/earthly to v0.8.15 (main)
2024-09-17 11:49:59 -07:00
Nic Cope 66d85f7042
Merge pull request #773 from crossplane/renovate/main-dario.cat-mergo-1.x
fix(deps): update module dario.cat/mergo to v1.0.1 (main)
2024-09-17 11:49:17 -07:00
crossplane-renovate[bot] ac06f0b886
fix(deps): update module dario.cat/mergo to v1.0.1 2024-09-15 08:05:40 +00:00
Philippe Scorsolini dbb3a5205d
Merge pull request #769 from crossplane/renovate/main-github-codeql-action-digest
chore(deps): update github/codeql-action digest to 8214744 (main)
2024-09-14 11:07:21 +01:00
crossplane-renovate[bot] 3f15d284a8
chore(deps): update github/codeql-action digest to 8214744 2024-09-14 08:03:56 +00:00
crossplane-renovate[bot] 8fa6609cc0
chore(deps): update actions/create-github-app-token digest to 5d869da 2024-09-12 08:04:35 +00:00
crossplane-renovate[bot] 2924c058b5
chore(deps): update dependency earthly/earthly to v0.8.15 2024-09-07 08:04:13 +00:00
crossplane-renovate[bot] fa3afb7588
chore(deps): update actions/checkout action to v4.1.7 2024-09-06 08:04:06 +00:00
crossplane-renovate[bot] 0d4fc05190
chore(deps): update docker/login-action digest to 9780b0c 2024-09-05 08:04:29 +00:00
Jared Watts 4afd09bc3c
Merge pull request #766 from jeanduplessis/main
Code updates after renaming `master` → `main`
2024-09-04 11:56:23 -07:00
Jean du Plessis db3fe7f1a2
Updates repo links, workflow configurations and other references from master to main.
Signed-off-by: Jean du Plessis <jean@upbound.io>
2024-09-03 14:35:01 +02:00
Philippe Scorsolini ac319f9f7b
Merge pull request #765 from ezgidemirel/update-stale-bot
Update stale bot to use the stale action as in Crossplane repo
2024-09-03 11:31:15 +02:00
ezgidemirel e7ba75a2c3
Update stale bot to use the stale action as in Crossplane repo
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-09-03 11:16:02 +02:00
Philippe Scorsolini f6428ca0e4
Merge pull request #763 from crossplane/renovate/master-codecov-codecov-action-digest 2024-09-01 10:19:59 +02:00
crossplane-renovate[bot] 02be488842
chore(deps): update codecov/codecov-action digest to e28ff12 2024-09-01 08:03:48 +00:00
Maximilian Blatt 3b73e8ea2d feat: Upgrade controller-runtime to v0.19.0
Adjust code to apply to breaking changes in controller-runtime. There
should be no breaking changes for programs using crossplane-runtime.

Signed-off-by: Maximilian Blatt <maximilian.blatt-extern@deutschebahn.com>
2024-08-26 11:49:19 +02:00
Maximilian Blatt 7f2eeb148c feat(managed): Add generic interfaces for external types
Add a wrapper for typed external clients that take over the conversion
from resource.Managed to the actual Go struct that is always necessary
in every controller.

It does not reduce complexity as a whole but allows controllers to save
some LoCs and focus on the important things.

Keep the previous types as type aliases to avoid any breaking changes.

Signed-off-by: Maximilian Blatt <maximilian.blatt-extern@deutschebahn.com>
2024-08-23 12:21:59 +02:00
Philippe Scorsolini 089f5f2347
Merge pull request #759 from phisco/release-1.17-empty-commit
Empty commit after release-1.17
2024-08-13 11:06:00 +02:00
Philippe Scorsolini a7a3602340
Empty commit after release-1.17
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-08-13 11:05:21 +02:00
Philippe Scorsolini edccdbc4af
Merge pull request #758 from phisco/fix-generate-post-buf-bump
fix: regenerate with buf 1.36.0
2024-08-12 11:36:37 +02:00
Philippe Scorsolini c810db4116
fix: regenerate with buf 1.36.0
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-08-12 11:31:09 +02:00
Philippe Scorsolini 6bdfe33c1c
Merge pull request #755 from phisco/bump-buf-1.36.0
chore(deps): bump bufbuild/buf to 1.36.0
2024-08-12 11:12:11 +02:00
Philippe Scorsolini 65e3ac0c7e
Merge pull request #733 from crossplane/renovate/master-google.golang.org-protobuf-1.x
fix(deps): update module google.golang.org/protobuf to v1.34.2 (master)
2024-08-12 11:07:04 +02:00
Philippe Scorsolini 1bffdd6e85
Merge pull request #741 from crossplane/renovate/master-actions-create-github-app-token-digest
chore(deps): update actions/create-github-app-token digest to 31c86eb (master)
2024-08-12 11:06:34 +02:00
Philippe Scorsolini cf1cac2008
chore(deps): bump bufbuild/buf to 1.36.0
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-08-12 10:27:20 +02:00
Jared Watts 1bb2e85926
Merge pull request #754 from jbw976/change-logs
Change logs support to track all changes being made to managed resources
2024-08-11 20:37:42 -07:00
Jared Watts cdc1561673
test: change logs unit tests
Signed-off-by: Jared Watts <jbw976@gmail.com>
2024-08-11 20:34:26 -07:00
Jared Watts 079cc1d02b
feat: change logs: support for tracking all changes made to managed resources
Signed-off-by: Jared Watts <jbw976@gmail.com>
2024-08-11 20:34:26 -07:00
Jared Watts 64763a22ad
feat: change logs protobuf/gRPC definitions
Signed-off-by: Jared Watts <jbw976@gmail.com>
2024-08-11 20:26:55 -07:00
Bob Haddleton 1e7193e9c0
Merge pull request #745 from ravilr/externalClient_disconnect
Disconnect() on per reconcile loop scoped external client
2024-07-22 12:49:32 -05:00
ravilr 84ee48af6f Disconnect() on per reconcile loop scoped external client
Signed-off-by: ravilr <raviprasad_lr@yahoo.com>
2024-07-15 15:35:10 -07:00
crossplane-renovate[bot] b7faf21d82
chore(deps): update actions/create-github-app-token digest to 31c86eb 2024-07-02 08:04:22 +00:00
Nic Cope ecb6ceeebe
Merge pull request #740 from crossplane/renovate/master-actions-checkout-digest
chore(deps): update actions/checkout digest to 692973e (master)
2024-07-01 11:59:25 -07:00
crossplane-renovate[bot] ee1e72e0cf
chore(deps): update actions/checkout digest to 692973e 2024-07-01 08:04:39 +00:00
Philippe Scorsolini 538156eb78
Merge pull request #735 from crossplane/renovate/master-github-codeql-action-digest
chore(deps): update github/codeql-action digest to b611370 (master)
2024-06-30 22:50:09 +02:00
crossplane-renovate[bot] 380f90a571
chore(deps): update github/codeql-action digest to b611370 2024-06-29 08:03:53 +00:00
Nic Cope 063a027390
Merge pull request #738 from dalton-hill-0/fn-conditions
Composite Receiver Functions for Conditions
2024-06-27 18:46:13 -07:00
dalton hill 2d6e2aeecd Composite receiver functions for conditions.
Signed-off-by: Dalton Hill <dalton.hill.0@protonmail.com>
2024-06-26 10:36:39 -05:00
crossplane-renovate[bot] 1f2a667f8c
fix(deps): update module google.golang.org/protobuf to v1.34.2 2024-06-12 08:05:46 +00:00
Nic Cope 77ead40fdb
Merge pull request #731 from crossplane/renovate/master-github.com-prometheus-client_golang-1.x
fix(deps): update module github.com/prometheus/client_golang to v1.19.1 (master)
2024-05-30 14:37:39 -07:00
Nic Cope 424d7b06d1
Merge pull request #729 from crossplane/renovate/master-github.com-evanphx-json-patch-5.x
fix(deps): update module github.com/evanphx/json-patch to v5.9.0+incompatible (master)
2024-05-30 14:37:07 -07:00
crossplane-renovate[bot] ae63110502
fix(deps): update module github.com/prometheus/client_golang to v1.19.1 2024-05-30 21:15:24 +00:00
crossplane-renovate[bot] b307d4c524
fix(deps): update module github.com/evanphx/json-patch to v5.9.0+incompatible 2024-05-30 21:15:08 +00:00
Nic Cope a4e82d5fdb
Merge pull request #730 from negz/third-rock-from-the-sun
Use GitHub releases, not tags, for Earthfile deps
2024-05-30 14:11:40 -07:00
Nic Cope 6be046b08f
Merge pull request #728 from crossplane/renovate/master-zeebe-io-backport-action-2.x
chore(deps): update zeebe-io/backport-action action to v2.5.0 (master)
2024-05-30 13:58:23 -07:00
Nic Cope 00bf85c7dd Use GitHub releases, not tags, for Earthfile deps
Notably CodeQL seems to have a tag cut that doesn't exist as a release.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-30 13:55:56 -07:00
Nic Cope 2c8b976927
Merge pull request #725 from crossplane/renovate/master-github.com-go-logr-logr-1.x
fix(deps): update module github.com/go-logr/logr to v1.4.2 (master)
2024-05-30 13:52:12 -07:00
crossplane-renovate[bot] 2762ad4f84
chore(deps): update zeebe-io/backport-action action to v2.5.0 2024-05-30 20:48:46 +00:00
crossplane-renovate[bot] 5a1728aafc
fix(deps): update module github.com/go-logr/logr to v1.4.2 2024-05-30 20:48:42 +00:00
Nic Cope d388e55843
Merge pull request #727 from negz/third-rock-from-the-sun
Don't drop privs to ubuntu before running Renovate
2024-05-30 13:44:57 -07:00
Nic Cope f65420ecbc Don't drop privs to ubuntu before running Renovate
It seems like earthly bootstrap can talk to docker, but earthly
+go-generate can't. My best guess is this is because we bootstrap as
root, then try to run earthly as ubuntu.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-30 13:41:32 -07:00
Nic Cope 4f7275b11e
Merge pull request #723 from negz/third-rock-from-the-sun
Allow Renovate to run Earthly
2024-05-30 12:04:35 -07:00
Philippe Scorsolini 0385660daf
Merge pull request #724 from crossplane/renovate/master-golang-version
chore(deps): update dependency go to v1.22.3 (master)
2024-05-30 09:32:52 +01:00
crossplane-renovate[bot] a3261c5c33
chore(deps): update dependency go to v1.22.3 2024-05-30 08:04:08 +00:00
Nic Cope 7305ea79f9 Allow Renovate to run Earthly
Actually install it in the Renovate container, not the runner
environment.

Also, run make rather than earthly on release branches.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 19:38:34 -07:00
Nic Cope 237bf40478
Merge pull request #713 from crossplane/renovate/master-earthly-earthly-0.x
chore(deps): update dependency earthly/earthly to v0.8.13 (master)
2024-05-29 18:40:48 -07:00
Nic Cope a5bd9cc849
Merge pull request #712 from crossplane/renovate/master-actions-checkout-digest
chore(deps): update actions/checkout digest to a5ac7e5 (master)
2024-05-29 18:39:30 -07:00
crossplane-renovate[bot] 3ce4225620
chore(deps): update dependency earthly/earthly to v0.8.13 2024-05-30 01:36:03 +00:00
crossplane-renovate[bot] 8ce6b28146
chore(deps): update actions/checkout digest to a5ac7e5 2024-05-30 01:35:59 +00:00
Nic Cope e4db79efcd
Merge pull request #711 from negz/third-rock-from-the-sun
Configure buf for BSR pushes
2024-05-29 18:25:25 -07:00
Nic Cope b3c1cef107 Fix EARTHLY_VERSION matching in GitHub Workflows
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 18:18:32 -07:00
Nic Cope ac285ed3c0 Configure buf for BSR pushes
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 18:05:11 -07:00
Nic Cope 6e15cd4e76
Merge pull request #698 from negz/third-rock-from-the-sun
Switch from Makefile to Earthly
2024-05-29 17:41:55 -07:00
Nic Cope e977812f6d Fix extra ' in check-diff job
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 16:00:23 -07:00
Nic Cope f50dd7dabc Ignore buf linter warning about incorrect package
Changing this package would be a breaking change.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 16:00:23 -07:00
Nic Cope 703577426f Update CODEOWNERS to reflect current state
This syncs with what we currently have in c/c. In practice we've dropped
reviewers because everything blocks on reviewers.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 15:43:46 -07:00
Nic Cope cf4876673c Port renovate config from c/c too
This implies switching from the Renovate app to the Renovate action.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 15:41:14 -07:00
Nic Cope ef0fdfa63d Fix linter issues surfaced by new linter config
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 15:37:39 -07:00
Nic Cope 4b32f0e040 Strip down build and CI to only things runtime needs
Removes all jobs and targets that are specific to crossplane/crossplane.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 15:37:39 -07:00
Nic Cope 04814f24f8 Copy Earthfile and friends from c/crossplane
Unmodified for now. I'll strip out everything this repo doesn't need in
a follow-up commit.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 15:20:53 -07:00
Nic Cope bf15ce0295 Remove Makefile and build submodule
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-29 15:20:35 -07:00
Nic Cope fc036618ff
Merge pull request #689 from negz/engine-swap
Bump controller-runtime to latest, remove the controller engine and GVK routed cache
2024-05-20 13:34:51 -07:00
Nic Cope 091d1b660a Bump controller-runtime to v0.18.2
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-17 12:21:33 -07:00
Nic Cope 8aa1c03caa Don't include buf as a dependency
It requires a newer cel-go dependency than the Kubernetes dependencies,
which makes updating them difficult.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-17 12:21:33 -07:00
Nic Cope 88ae9393e6 Bump protobuf and Kubernetes dependencies
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-17 12:21:33 -07:00
Nic Cope 62e5021574 Delete the controller engine
It's breaking the dependencies of this module, and its only consumer is
the c/c repo. It should live there instead.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-17 12:21:33 -07:00
Nic Cope 23c644178e
Merge pull request #693 from negz/its-happening-dot-gif
Switch to the crossplane/build submodule
2024-05-16 10:22:31 -07:00
Nic Cope bf08434192 Switch to the crossplane/build submodule
Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-05-15 17:56:17 -07:00
Hasan Turken e50f51abfe
Merge pull request #692 from turkenh/allow-observe-update
Whitelist management policy Observe & Update
2024-05-13 15:38:22 +03:00
Hasan Turken e739ce37ae
Whitelist management policy Observe & Update
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2024-05-13 15:10:09 +03:00
Nic Cope b31be7747c
Merge pull request #688 from ezgidemirel/fix-mr-state
Fix MR state metrics when MRs are deleted
2024-05-09 11:20:37 -07:00
ezgidemirel 78ccb5f030
Fix MR state metrics when MRs are deleted
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-05-09 18:28:31 +03:00
Jared Watts e477558289
Merge pull request #690 from jbw976/empty-master
Empty commit after release-1.16
2024-05-07 09:41:09 +02:00
Jared Watts e83268677c
Empty commit after release-1.16
Signed-off-by: Jared Watts <jbw976@gmail.com>
2024-05-07 09:37:30 +02:00
Hasan Turken 8641eb2ba3
Merge pull request #683 from ezgidemirel/mr-metrics
Introduce High Level MR metrics
2024-04-24 14:46:34 +03:00
Philippe Scorsolini 590e44d838
Merge pull request #685 from crossplane/renovate/go-golang.org/x/net-vulnerability 2024-04-20 17:00:30 +01:00
renovate[bot] c849e1abf3
Update module golang.org/x/net to v0.23.0 [SECURITY] 2024-04-20 13:44:09 +00:00
Nic Cope b121916247
Merge pull request #633 from pedjak/add-reconcile-observation
Add ability to expose resource reconciliation progress
2024-04-19 15:03:35 -07:00
Predrag Knezevic d049fcc2e9 Address reviewer comments
Signed-off-by: Predrag Knezevic <predrag.knezevic@upbound.io>
2024-04-19 15:47:18 +02:00
ezgidemirel 249f4c09be
remove XRStateMetrics
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-04-18 15:44:32 +03:00
ezgidemirel aa7264baf4
make state recorders Runnable and remove unstructured listing
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-04-16 20:01:05 +03:00
ezgidemirel 4b6c2de666
add XR state metrics
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-04-16 11:36:10 +03:00
Predrag Knezevic b5462b512d Add ability to expose resource reconciliation progress
* `status.observedGeneration` fields has been added to claim/composite/composed status,
  showing the latest metadata.generation which resulted in either a ready state,
  or stalled due to error it can not recover from without human intervention.
* `status.conditions[x].observedGeneration represents the .metadata.generation
  that the condition was set based upon

Signed-off-by: Predrag Knezevic <predrag.knezevic@upbound.io>
2024-04-09 11:04:31 +02:00
ezgidemirel af6588856c
change init pattern and move state metrics to a go routine
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-04-08 18:48:05 +03:00
ezgidemirel 64074c3e5d
Add High Level MR metrics
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2024-04-03 16:16:14 +03:00
Dr. Stefan Schimanski b42479383b
reconciler/managed: add crossplane_resource_drift_seconds metric
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2024-04-02 17:18:39 +03:00
Nic Cope 991de68a3f
Merge pull request #677 from crossplane/renovate/actions-cache-digest
Update actions/cache digest to ab5e6d0
2024-03-05 13:34:58 -08:00
renovate[bot] 4deaf95f43
Update actions/cache digest to ab5e6d0 2024-03-05 10:02:34 +00:00
Philippe Scorsolini 22f4f4b76a
Merge pull request #676 from negz/my-pockets-are-full 2024-03-05 10:01:54 +00:00
Nic Cope 2c81cc6326
Merge pull request #673 from sttts/sttts-klog-throttling
logging: add SetFilteredKlogLogger to show client-go throttling logs
2024-02-26 14:33:05 -08:00
Dr. Stefan Schimanski 5f2a2782ca
logging: add SetFilteredKlogLogger to show client-go throttling logs
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2024-02-23 09:01:22 +01:00
Nic Cope feb7810cc1
Merge pull request #667 from crossplane/renovate/golang-1.x
Update dependency golang to v1.22.0
2024-02-20 17:23:27 -08:00
Nic Cope 0c7b1eb549 Bump golangci-lint, copy config from c/c
This copies the latest config from c/c and addresses all the linter
errors that config produces.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2024-02-20 03:45:27 -08:00
Philippe Scorsolini 7fcb8c5cad
Merge pull request #666 from sergenyalcin/handle-nil-case 2024-02-13 13:46:10 +00:00
Sergen Yalçın 195a02da31
Change the error message with a more consistent with the other errors
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2024-02-13 16:01:25 +03:00
Philippe Scorsolini 229b63d399
Merge pull request #664 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to e8893c5
2024-02-12 09:15:33 +00:00
Philippe Scorsolini 87e9df8961
Merge pull request #661 from crossplane/renovate/codecov-codecov-action-digest
Update codecov/codecov-action digest to e0b68c6
2024-02-12 09:14:52 +00:00
Sergen Yalçın b1cd25a73b
Change the error message
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2024-02-07 11:18:55 +03:00
renovate[bot] 8d8d493362
Update dependency golang to v1.22.0 2024-02-07 01:19:15 +00:00
Sergen Yalçın 5cd11c97cb
Add a nil case to the getValueFromInterface function
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2024-02-06 19:32:18 +03:00
Philippe Scorsolini 3307c237d9
Merge pull request #665 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.17.0
2024-02-06 09:56:58 +00:00
renovate[bot] 5caac07188
Update aquasecurity/trivy-action action to v0.17.0 2024-02-06 03:53:56 +00:00
renovate[bot] d9219be715
Update github/codeql-action digest to e8893c5 2024-02-02 21:01:02 +00:00
renovate[bot] 524c25cedc
Update codecov/codecov-action digest to e0b68c6 2024-02-02 01:52:56 +00:00
Philippe Scorsolini fa4ffff0a5
Merge pull request #630 from crossplane/renovate/kubernetes-deps
Update kubernetes deps
2024-02-01 16:24:59 +00:00
Philippe Scorsolini 88865715a0
fix: add RemoveInformer to implement Informers
Co-authored-by: Maximilian Blatt <maximilian.blatt-extern@deutschebahn.com>
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-01-31 15:05:57 +00:00
Philippe Scorsolini e0bda77c3c
Merge pull request #647 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.61.0
2024-01-31 14:06:19 +00:00
renovate[bot] 212afb1dc1
Update module google.golang.org/grpc to v1.61.0 2024-01-31 14:03:53 +00:00
renovate[bot] d05b5c2d78
Update kubernetes deps 2024-01-31 14:03:25 +00:00
Philippe Scorsolini c50d4ff5e6
Merge pull request #656 from phisco/we-want-old-stuff
chore(deps): revert to buf 1.27.2 to avoid cel-go dependency ahead of k8s deps
2024-01-31 14:02:24 +00:00
Philippe Scorsolini a69323df23
chore(deps): revert to buf 1.27.2 to avoid cel-go dependency ahead of k8s deps
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-01-30 10:08:10 +00:00
Philippe Scorsolini 93bd0c2b12
Merge pull request #651 from sttts/sttts-critical-annotation-non-api-errors
reconciler/managed: make more resilient to error conditions
2024-01-29 13:47:25 +00:00
Dr. Stefan Schimanski 34c3e60a06
reconciler/managed: don't brick MR on create conflict
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2024-01-27 16:01:56 +01:00
Dr. Stefan Schimanski 7d7a4e9273
reconciler/managed: keep trying to update critical annotation until ctx canceled
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2024-01-27 15:59:19 +01:00
Nic Cope eb0fbf149f
Merge pull request #650 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to b7bf0a3
2024-01-26 16:10:12 -08:00
renovate[bot] 5d134fad10
Update github/codeql-action digest to b7bf0a3 2024-01-26 15:13:00 +00:00
Philippe Scorsolini 5400fe5c11
Merge pull request #649 from phisco/release-1.15-empty
Empty commit for 1.15 release
2024-01-26 15:12:41 +00:00
Philippe Scorsolini 94f453f296
Empty commit for 1.15 release
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-01-26 15:10:09 +00:00
Bob Haddleton f4310f0291
Merge pull request #646 from crossplane/renovate/zeebe-io-backport-action-2.x
Update zeebe-io/backport-action action to v2.4.1
2024-01-24 16:24:27 -06:00
Bob Haddleton f46d8e0e45
Merge pull request #648 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.29.0
2024-01-24 16:22:35 -06:00
renovate[bot] 855bd8933e
Update module github.com/bufbuild/buf to v1.29.0 2024-01-24 22:17:04 +00:00
renovate[bot] ae46956391
Update zeebe-io/backport-action action to v2.4.1 2024-01-23 19:21:13 +00:00
Nic Cope 87cb2d83e2
Merge pull request #641 from sttts/sttts-engine-waitforsync
controller/engine: sync informers on controller start
2024-01-22 16:16:42 -08:00
Nic Cope d3ff9c2802
Merge pull request #645 from crossplane/renovate/zeebe-io-backport-action-2.x
Update zeebe-io/backport-action action to v2.4.0
2024-01-22 16:16:22 -08:00
renovate[bot] 5849dcfe6b
Update zeebe-io/backport-action action to v2.4.0 2024-01-22 18:07:59 +00:00
Nic Cope ed7658c003
Merge pull request #643 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 0b21cf2
2024-01-17 11:06:14 -08:00
Nic Cope 67e2d2213a
Merge pull request #644 from crossplane/renovate/actions-cache-4.x
Update actions/cache action to v4
2024-01-17 11:05:48 -08:00
renovate[bot] 4f8b6c344a
Update actions/cache action to v4 2024-01-17 18:24:28 +00:00
renovate[bot] 9f3be70946
Update github/codeql-action digest to 0b21cf2 2024-01-17 18:24:23 +00:00
Nic Cope 86552e349d
Merge pull request #642 from crossplane/renovate/actions-cache-digest
Update actions/cache digest to e12d46a
2024-01-11 11:24:40 -08:00
renovate[bot] e2b8d1fe90
Update actions/cache digest to e12d46a 2024-01-11 18:51:15 +00:00
Philippe Scorsolini 1b3f43edab
Merge pull request #640 from crossplane/renovate/golang-1.x
Update dependency golang to v1.21.6
2024-01-11 14:09:41 +00:00
Dr. Stefan Schimanski 7f21c79d63
controller/engine: sync informers on controller start
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2024-01-09 23:13:56 +01:00
renovate[bot] d04d95fea6
Update dependency golang to v1.21.6 2024-01-09 19:13:00 +00:00
Philippe Scorsolini 3fb59b8eef
Merge pull request #632 from crossplane/renovate/github.com-go-logr-logr-1.x
Update module github.com/go-logr/logr to v1.4.1
2024-01-09 15:19:17 +00:00
Philippe Scorsolini 45da514a81
Merge pull request #631 from crossplane/renovate/zeebe-io-backport-action-2.x
Update zeebe-io/backport-action action to v2.3.0
2024-01-09 15:18:46 +00:00
Philippe Scorsolini eb1fd22cd3
Merge pull request #639 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.16.1
2024-01-08 14:21:26 +00:00
renovate[bot] 7d432a2400
Update aquasecurity/trivy-action action to v0.16.1 2024-01-08 14:02:26 +00:00
Philippe Scorsolini e3150edf97
Merge pull request #638 from crossplane/renovate/github-codeql-action-digest 2024-01-08 14:02:10 +00:00
renovate[bot] be06a7ba77
Update github/codeql-action digest to e5f05b8 2024-01-08 13:42:46 +00:00
Philippe Scorsolini 92d15eb7db
Merge pull request #637 from crossplane/renovate/github-codeql-action-digest 2024-01-08 10:51:31 +01:00
renovate[bot] 47a0675ea9
Update github/codeql-action digest to 012739e 2024-01-08 09:44:12 +00:00
Philippe Scorsolini 939dd07241
Merge pull request #636 from crossplane/renovate/google.golang.org-protobuf-1.x
Update module google.golang.org/protobuf to v1.32.0
2024-01-08 10:43:55 +01:00
Philippe Scorsolini 82a275c817
chore: regenerate with protobuf 1.32.0
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2024-01-08 09:41:27 +00:00
Philippe Scorsolini 1f274ea970
Merge pull request #626 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.60.1
2024-01-08 10:14:46 +01:00
renovate[bot] d0ba8abf59
Update module google.golang.org/grpc to v1.60.1 2024-01-08 08:52:01 +00:00
Philippe Scorsolini 31cfd49181
Merge pull request #634 from crossplane/renovate/go-golang.org/x/crypto-vulnerability
Update module golang.org/x/crypto to v0.17.0 [SECURITY]
2024-01-08 09:51:34 +01:00
Nic Cope bc3a043a97
Merge pull request #635 from sttts/sttts-external-client-namespaced
reconciler/managed: fix RetryingCriticalAnnotationUpdater to support namespaces
2024-01-05 12:41:35 -08:00
Dr. Stefan Schimanski 1355caff8e
reconciler/managed: fix RetryingCriticalAnnotationUpdater to support namespaces
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2024-01-05 18:23:56 +01:00
renovate[bot] 1975bccc3f
Update module golang.org/x/crypto to v0.17.0 [SECURITY] 2024-01-04 16:07:54 +00:00
renovate[bot] b7a65e7205
Update module google.golang.org/protobuf to v1.32.0 2023-12-22 10:28:29 +00:00
renovate[bot] 34f252b793
Update module github.com/go-logr/logr to v1.4.1 2023-12-21 21:22:52 +00:00
renovate[bot] 28af4ef324
Update zeebe-io/backport-action action to v2.3.0 2023-12-16 16:01:45 +00:00
Philippe Scorsolini d23a82b3a2
Merge pull request #629 from crossplane/renovate/github-codeql-action-3.x
Update github/codeql-action action to v3
2023-12-15 10:17:46 +01:00
renovate[bot] 0c56073ac0
Update github/codeql-action action to v3 2023-12-15 09:16:57 +00:00
Philippe Scorsolini de819762ea
Merge pull request #628 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 03e7845
2023-12-15 10:16:42 +01:00
renovate[bot] f2507ff4a4
Update github/codeql-action digest to 03e7845 2023-12-13 22:30:18 +00:00
Hasan Turken 0b379538ab
Merge pull request #627 from sergenyalcin/handle-nil-value-paved
Add a nil case to the expandWildcards function
2023-12-13 10:14:10 +03:00
Sergen Yalçın 4e24aae89d
- Used %q in the error message
- Added a unit-test case

Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2023-12-12 15:00:40 +03:00
Sergen Yalçın cac4c15ef3
Add a nil case to the expandWildcards function
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2023-12-12 13:09:14 +03:00
Hasan Turken 8d1435650d
Merge pull request #623 from ulucinar/ssa-simple-api-resolver
Use server-side apply patch to update the resolved cross-resource references
2023-12-11 16:57:45 +03:00
Philippe Scorsolini 86977d4a05
Merge pull request #624 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.16.0
2023-12-11 09:31:52 +01:00
renovate[bot] 5c7361e9bf
Update aquasecurity/trivy-action action to v0.16.0 2023-12-08 19:48:39 +00:00
Philippe Scorsolini 636ba23a50
Merge pull request #621 from crossplane/renovate/actions-setup-go-5.x
Update actions/setup-go action to v5
2023-12-08 16:32:24 +01:00
Alper Rifat Ulucinar f1be5e62dc
Use server-side apply patch to update the resolved cross-resource references
in managed.APISimpleReferenceResolver.

Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2023-12-08 15:04:53 +03:00
Philippe Scorsolini 7471b4a589
Merge pull request #616 from crossplane/renovate/zeebe-io-backport-action-2.x
Update zeebe-io/backport-action action to v2.2.0
2023-12-07 17:52:46 +01:00
Philippe Scorsolini 1cec5fe950
Merge pull request #619 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.15.0
2023-12-07 17:00:22 +01:00
Philippe Scorsolini 0bae4cd1f5
Merge pull request #622 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to c0d1daa
2023-12-07 16:59:29 +01:00
renovate[bot] 8d95b22d16
Update github/codeql-action digest to c0d1daa 2023-12-07 11:46:48 +00:00
renovate[bot] eb1cad400c
Update actions/setup-go action to v5 2023-12-06 15:35:28 +00:00
Philippe Scorsolini 53f2f2d472
Merge pull request #620 from crossplane/renovate/golang-1.x 2023-12-05 20:42:45 +01:00
renovate[bot] d4e45610dc
Update dependency golang to v1.21.5 2023-12-05 19:35:27 +00:00
Hasan Turken 4697781787
Merge pull request #618 from ulucinar/fix-617
Treat all maps & slices of zero-length equal whether they are nil or not in managed.APISimpleReferenceResolver
2023-12-05 14:19:02 +03:00
renovate[bot] 279cf9cbf5
Update aquasecurity/trivy-action action to v0.15.0 2023-12-05 01:07:27 +00:00
Alper Rifat Ulucinar 3d34552fe9
Treat all maps & slices of zero-length equal whether they are nil or not in managed.APISimpleReferenceResolver
Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2023-12-04 18:43:59 +03:00
renovate[bot] 6c8a5634d2
Update zeebe-io/backport-action action to v2.2.0 2023-12-04 11:15:17 +00:00
Philippe Scorsolini fa372205d0
Merge pull request #614 from crossplane/renovate/google.golang.org-protobuf-digest
Update google.golang.org/protobuf digest to 2087447
2023-12-02 08:15:26 +01:00
renovate[bot] e49ba255e3
Update google.golang.org/protobuf digest to 2087447 2023-12-01 01:43:27 +00:00
Philippe Scorsolini ce34a9d134
Merge pull request #613 from lsviben/od-supported-policy
Add [Observe, Delete] as a supported management policy
2023-11-30 08:22:06 +01:00
Philippe Scorsolini 2cbf8d956c
Merge pull request #610 from eljohnson92/support_int_pointers
add support for int pointer references
2023-11-30 08:16:33 +01:00
Philippe Scorsolini 013a48df1f
Merge pull request #612 from crossplane/renovate/github.com-spf13-afero-1.x
Update module github.com/spf13/afero to v1.11.0
2023-11-30 08:12:33 +01:00
lsviben 40bf7a947d
add Observe Delete as a supported management policy
Signed-off-by: lsviben <sviben.lovro@gmail.com>
2023-11-29 15:19:51 +01:00
renovate[bot] f0c1e4c5db
Update module github.com/spf13/afero to v1.11.0 2023-11-28 11:45:46 +00:00
Philippe Scorsolini 799c0f8f27
Merge pull request #611 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 407ffaf
2023-11-27 08:50:50 +01:00
renovate[bot] 9ddd17253d
Update github/codeql-action digest to 407ffaf 2023-11-23 12:23:37 +00:00
Philippe Scorsolini ed91ef66a0
Merge pull request #607 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.28.1
2023-11-22 08:53:22 +01:00
Evan Johnson e8a5d63058 add support for int pointer references
Signed-off-by: Evan Johnson <eljohn1014@gmail.com>
2023-11-20 12:53:09 -05:00
Philippe Scorsolini c8449480cf
Merge pull request #609 from crossplane/renovate/actions-github-script-digest
Update actions/github-script digest to 60a0d83
2023-11-20 09:17:13 +01:00
renovate[bot] bbed54a73c
Update actions/github-script digest to 60a0d83 2023-11-17 22:56:04 +00:00
Philippe Scorsolini a4f4cee012
Merge pull request #608 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 66b90a5
2023-11-16 16:27:41 +01:00
renovate[bot] f87534f358
Update github/codeql-action digest to 66b90a5 2023-11-16 15:23:17 +00:00
Philippe Scorsolini e2b9965c23
Merge pull request #606 from crossplane/renovate/kubernetes-deps
Update kubernetes deps to v0.28.4
2023-11-16 16:23:02 +01:00
renovate[bot] 4bc55866ca
Update module github.com/bufbuild/buf to v1.28.1 2023-11-16 12:50:14 +00:00
renovate[bot] f280c92d4e
Update kubernetes deps to v0.28.4 2023-11-16 12:49:43 +00:00
Philippe Scorsolini 674cf9b384
Merge pull request #605 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 689fdc5
2023-11-16 13:49:12 +01:00
Philippe Scorsolini 5f50a2cd18
Merge pull request #602 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.28.0
2023-11-16 13:48:53 +01:00
Philippe Scorsolini e258edd7e2
Merge pull request #580 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.55.2
2023-11-16 13:48:32 +01:00
Philippe Scorsolini 0467f86082
chore(linting): use getters
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-11-16 12:14:24 +01:00
Philippe Scorsolini 4ed93de467
Merge pull request #604 from crossplane/renovate/actions-github-script-7.x
Update actions/github-script action to v7
2023-11-16 12:03:09 +01:00
renovate[bot] c44eaea136
Update github/codeql-action digest to 689fdc5 2023-11-16 08:27:26 +00:00
Philippe Scorsolini c917ad617a
Merge pull request #598 from crossplane/renovate/zeebe-io-backport-action-2.x
Update zeebe-io/backport-action action to v2.1.1
2023-11-16 09:27:11 +01:00
Philippe Scorsolini 030db66b22
fix: regenerate with new buf version
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-11-14 10:10:47 +01:00
renovate[bot] 1d28a35420
Update actions/github-script action to v7 2023-11-14 09:04:02 +00:00
Philippe Scorsolini dda83de4b5
Merge pull request #600 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.14.0
2023-11-14 10:03:38 +01:00
Nic Cope 24db9cb16f
Merge pull request #599 from negz/deeper-copy
Give unstructured types their own DeepCopy methods
2023-11-13 11:46:18 -08:00
renovate[bot] 4fd412522e
Update module github.com/bufbuild/buf to v1.28.0 2023-11-13 08:46:11 +00:00
renovate[bot] 62584046b2
Update dependency golangci/golangci-lint to v1.55.2 2023-11-13 08:45:39 +00:00
Philippe Scorsolini a59c28780b
Merge pull request #601 from crossplane/renovate/golang-1.x
Update dependency golang to v1.21.4
2023-11-13 10:45:19 +02:00
renovate[bot] db55c35025
Update zeebe-io/backport-action action to v2.1.1 2023-11-07 23:51:24 +00:00
renovate[bot] 69ca8eea3a
Update dependency golang to v1.21.4 2023-11-07 23:51:18 +00:00
renovate[bot] 5e41903835
Update aquasecurity/trivy-action action to v0.14.0 2023-11-07 01:42:45 +00:00
Nic Cope fab7762d2e Generate deepcopy methodsets for Unstructured types
Removes the tests - we don't need to test generated code.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-11-06 16:42:57 -08:00
Nic Cope d54c6046df Give unstructured types their own DeepCopy methods
Fixes https://github.com/crossplane/crossplane/issues/4970

These types all embed *unstructured.Unstructured. If they don't
implement their own DeepCopy methods, callers will end up calling those
of the embedded *Unstructured. The result is that a deepcopy isn't a
real copy - it's the wrong type (*unstructured.Unstructured).

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-11-05 14:51:44 -08:00
Hasan Turken 361222fc5c
Merge pull request #594 from turkenh/fix-critical-annotations-retry
Fix retry in update critical annotations after a confict
2023-11-02 12:54:26 +03:00
Hasan Turken 9aa1024097
Fix retry in update critical annotations
- A successful get after a conflict should not hide the conflict
error and prevent retries.

Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-11-02 12:06:06 +03:00
Nic Cope 11ba5f5ef6
Merge pull request #584 from crossplane/renovate/kubernetes-deps
Update module sigs.k8s.io/yaml to v1.4.0
2023-10-31 11:46:47 -07:00
Nic Cope 2902936dbd
Merge pull request #587 from crossplane/renovate/github.com-go-logr-logr-1.x
Update module github.com/go-logr/logr to v1.3.0
2023-10-31 11:46:19 -07:00
Nic Cope a7eaae974b
Merge pull request #592 from crossplane/renovate/go-github.com/docker/docker-vulnerability
Update module github.com/docker/docker to v24.0.7+incompatible [SECURITY]
2023-10-31 11:45:47 -07:00
renovate[bot] df437dadb9
Update module github.com/docker/docker to v24.0.7+incompatible [SECURITY] 2023-10-31 07:54:00 +00:00
Philippe Scorsolini 68c520abd3
Merge pull request #591 from crossplane/renovate/aquasecurity-trivy-action-0.x 2023-10-31 08:53:10 +01:00
renovate[bot] 64580bb2de
Update aquasecurity/trivy-action action to v0.13.1 2023-10-31 02:02:48 +00:00
Philippe Scorsolini bf7c5af8e6
Merge pull request #590 from crossplane/renovate/zeebe-io-backport-action-2.x
Update zeebe-io/backport-action action to v2
2023-10-30 09:28:48 +01:00
renovate[bot] 165766af57
Update module github.com/go-logr/logr to v1.3.0 2023-10-28 21:56:26 +00:00
Nic Cope e6fd3879f4
Merge pull request #589 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.27.2
2023-10-28 14:55:40 -07:00
renovate[bot] 47cf6cf5d5
Update zeebe-io/backport-action action to v2 2023-10-28 15:22:03 +00:00
renovate[bot] e8edd64416
Update module github.com/bufbuild/buf to v1.27.2 2023-10-27 21:36:20 +00:00
Philippe Scorsolini 9a89a4b2ba
Merge pull request #588 from crossplane/renovate/github-codeql-action-digest 2023-10-27 16:07:44 +02:00
renovate[bot] c5d86d08f8
Update github/codeql-action digest to 74483a3 2023-10-27 10:31:54 +00:00
Philippe Scorsolini ed1bf5bc80
Merge pull request #586 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.13.0
2023-10-26 09:37:12 +02:00
renovate[bot] 4aea522b40
Update aquasecurity/trivy-action action to v0.13.0 2023-10-25 20:00:39 +00:00
Hasan Turken 8223090f1a
Merge pull request #585 from turkenh/empty-past-1.14
Empty commit after release-1.14
2023-10-25 15:17:10 +03:00
Hasan Turken 8e926478ac
Empty commit after release-1.14
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-10-25 15:03:05 +03:00
renovate[bot] 350432f4c3
Update module sigs.k8s.io/yaml to v1.4.0 2023-10-24 21:56:21 +00:00
Philippe Scorsolini 288a6e5513
Merge pull request #582 from crossplane/renovate/fkirc-skip-duplicate-actions-5.x
Update fkirc/skip-duplicate-actions action to v5.3.1
2023-10-23 10:42:21 +02:00
Philippe Scorsolini 68bc840976
Merge pull request #581 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 49abf0b
2023-10-23 10:40:34 +02:00
renovate[bot] e685576eae
Update fkirc/skip-duplicate-actions action to v5.3.1 2023-10-21 07:00:44 +00:00
renovate[bot] 9727704e94
Update github/codeql-action digest to 49abf0b 2023-10-20 17:04:01 +00:00
Philippe Scorsolini a5df125af6
Merge pull request #578 from crossplane/renovate/kubernetes-deps
Update kubernetes deps
2023-10-19 17:28:56 +02:00
Philippe Scorsolini 479d7826fa
Merge pull request #579 from crossplane/renovate/actions-checkout-digest
Update actions/checkout digest to b4ffde6
2023-10-19 17:26:57 +02:00
renovate[bot] 185c052ef8
Update actions/checkout digest to b4ffde6 2023-10-19 11:24:27 +00:00
renovate[bot] 805aa2c035
Update kubernetes deps 2023-10-18 19:56:45 +00:00
Philippe Scorsolini f2f755cdc4
Merge pull request #577 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.59.0
2023-10-18 11:12:29 +02:00
renovate[bot] 3a8735a962
Update module google.golang.org/grpc to v1.59.0 2023-10-18 00:20:23 +00:00
Philippe Scorsolini 89e89660b5
Merge pull request #576 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.27.1
2023-10-17 09:13:54 +02:00
renovate[bot] dc82dff2c4
Update module github.com/bufbuild/buf to v1.27.1 2023-10-17 00:47:42 +00:00
Nic Cope 674082aae6
Merge pull request #575 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 0116bc2
2023-10-13 18:08:37 -07:00
Nic Cope 184c672cca
Merge pull request #574 from crossplane/renovate/go-golang.org/x/net-vulnerability
Update module golang.org/x/net to v0.17.0 [SECURITY]
2023-10-13 18:08:18 -07:00
Nic Cope 80a3e75d99
Merge pull request #554 from sttts/sttts-engine-cached-client
controller/engine: use local cache for client read requests
2023-10-13 14:17:18 -07:00
renovate[bot] 6d1cd833aa
Update github/codeql-action digest to 0116bc2 2023-10-13 13:17:29 +00:00
Dr. Stefan Schimanski 8c70e452b0
Revert back to interface
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-10-13 12:10:45 +02:00
Dr. Stefan Schimanski d77466ecd2
controller/engine: split controller creation and start
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-10-13 11:48:06 +02:00
Dr. Stefan Schimanski 33981937cc
controller/engine: merge parent and local cache
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-10-13 11:48:06 +02:00
renovate[bot] ca8149fe21
Update module golang.org/x/net to v0.17.0 [SECURITY] 2023-10-13 09:29:33 +00:00
Philippe Scorsolini d5bf0794d1
Merge pull request #573 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to d90b8d7
2023-10-13 11:28:47 +02:00
renovate[bot] 63eff2a8a7
Update github/codeql-action digest to d90b8d7 2023-10-12 12:17:56 +00:00
Philippe Scorsolini cc691421c2
Merge pull request #570 from crossplane/renovate/golang-1.x
Update dependency golang to v1.21.3
2023-10-11 09:03:44 +02:00
Philippe Scorsolini d700d0eb79
Merge pull request #572 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.58.3
2023-10-11 09:02:34 +02:00
renovate[bot] f020b8f7c4
Update module google.golang.org/grpc to v1.58.3 2023-10-10 22:04:18 +00:00
Philippe Scorsolini 2819f51569
Merge pull request #571 from crossplane/renovate/github.com-google-go-cmp-0.x 2023-10-10 21:12:26 +02:00
renovate[bot] 384e6d9570
Update module github.com/google/go-cmp to v0.6.0 2023-10-10 19:06:40 +00:00
renovate[bot] 713904d95f
Update dependency golang to v1.21.3 2023-10-10 19:06:05 +00:00
Hasan Turken a8f7557409
Merge pull request #552 from pedjak/fix-claimRef-set
SetClaimReference must pass to underlying object just claimRef allowed fields
2023-10-10 07:22:32 +03:00
Philippe Scorsolini f7e1e8aace
Merge pull request #569 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to fdcae64
2023-10-09 14:23:48 +02:00
Predrag Knezevic 81b21d47fe fix(pkg/resource/composite) drop usage of ObjectReference in SetClaimReference
`spec.claimRef` schema is just subset of corev1.ObjectReference, and hence
`SetClaimReference` might get a reference that have more fields set, e.g. UID.
The fields that do not exist in claimRef schema must be not set on the underlying object,
otherwise K8s API server complains about non-existing field when client sends a patch request.

* Introduced `claim.Reference` type that corresponds to `spec.claimRef` schema.
* `composite.SetClaimReference` signature changed to accept an instance of `claim.Reference`
* appropriate tests updated/new tests added

Signed-off-by: Predrag Knezevic <predrag.knezevic@upbound.io>
2023-10-09 13:53:55 +02:00
renovate[bot] 3983447b28
Update github/codeql-action digest to fdcae64 2023-10-09 11:07:11 +00:00
Philippe Scorsolini baf8621383
Merge pull request #568 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 2cb752a
2023-10-08 10:16:02 +02:00
renovate[bot] 283b0c87bd
Update github/codeql-action digest to 2cb752a 2023-10-06 12:11:17 +00:00
Philippe Scorsolini f8da8fe285
Merge pull request #566 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.27.0
2023-10-06 10:11:09 +02:00
Philippe Scorsolini ab7191b89b
Merge pull request #567 from crossplane/renovate/golang-1.x
Update dependency golang to v1.21.2
2023-10-06 09:44:04 +02:00
renovate[bot] 8aa92429e1
Update dependency golang to v1.21.2 2023-10-05 22:19:53 +00:00
renovate[bot] 1542723c76
Update module github.com/bufbuild/buf to v1.27.0 2023-10-05 00:30:57 +00:00
Hasan Turken b537456800
Merge pull request #565 from lsviben/fix-import
fix missing import
2023-10-03 12:50:54 +03:00
lsviben 3e9d757b6c
fix missing import
Signed-off-by: lsviben <sviben.lovro@gmail.com>
2023-10-03 10:04:24 +02:00
Hasan Turken 075b3d5fb8
Merge pull request #556 from sttts/sttts-silently-ignore-conflicts
errors: add SilentlyRequeueOnConflicts
2023-10-02 13:28:09 +03:00
Nic Cope f0d05be088
Merge pull request #564 from phisco/conditions-schema-as-map
feat: add annotations to ConditionedStatus to make conditions a map
2023-09-28 09:47:20 -07:00
Philippe Scorsolini dbdff6e2ad
feat: add annotations to ConditionedStatus to make conditions a map
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-09-28 12:23:19 +02:00
Philippe Scorsolini 54f79f799e
Merge pull request #562 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to ddccb87
2023-09-28 10:21:35 +02:00
renovate[bot] c5b617e0bb
Update github/codeql-action digest to ddccb87 2023-09-27 15:23:05 +00:00
Philippe Scorsolini c05e74a4b5
Merge pull request #540 from phisco/fix/conflict-errors-remake-2 2023-09-26 18:40:23 +02:00
Dr. Stefan Schimanski 8333c5c0bd
reconciler/managed: simplify conflict suppression with helper
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-09-26 16:20:56 +02:00
Dr. Stefan Schimanski 712d0dbc69
errors: add SilentlyRequeueOnConflicts
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-09-26 16:20:56 +02:00
Philippe Scorsolini 4c4b0b47b6
Merge pull request #558 from crossplane/renovate/github.com-spf13-afero-1.x
Update module github.com/spf13/afero to v1.10.0
2023-09-26 10:30:22 +02:00
Philippe Scorsolini 8ace3830a7
Merge pull request #561 from ulucinar/fix-acp 2023-09-25 17:11:00 +02:00
Alper Rifat Ulucinar 95e05915a4
Do not modify the informer cache objects in resource.AnnotationChangedPredicate.Update
Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2023-09-25 15:36:17 +03:00
Philippe Scorsolini af24dc1b2f
Merge pull request #559 from crossplane/renovate/actions-checkout-digest
Update actions/checkout digest to 8ade135
2023-09-25 09:56:26 +02:00
renovate[bot] 9e3dd80447
Update actions/checkout digest to 8ade135 2023-09-22 19:40:00 +00:00
renovate[bot] fbed6b23e3
Update module github.com/spf13/afero to v1.10.0 2023-09-22 16:52:36 +00:00
Philippe Scorsolini b82c293947
Merge pull request #553 from lsviben/lintable 2023-09-22 12:49:57 +02:00
Philippe Scorsolini 3e58adca9b
Merge pull request #557 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.58.2
2023-09-22 12:30:04 +02:00
lsviben 3edf846d8f
add docs
Signed-off-by: lsviben <sviben.lovro@gmail.com>
2023-09-22 11:25:03 +02:00
renovate[bot] e892cf3257
Update module google.golang.org/grpc to v1.58.2 2023-09-22 00:12:53 +00:00
Philippe Scorsolini 2d96b39e1e
Merge pull request #548 from phisco/avoid-dropping-commented-lines
fix(package parser): only drop fully commented files
2023-09-21 11:39:49 +02:00
Hasan Turken 9597f2ac5a
Merge pull request #549 from lsviben/gmp-to-beta
GMP to beta
2023-09-20 16:29:02 +03:00
lsviben a6045dd880
introduce Lintable
Signed-off-by: lsviben <sviben.lovro@gmail.com>
2023-09-20 14:55:48 +02:00
lsviben 55a8c10930
gmp to beta
Signed-off-by: lsviben <sviben.lovro@gmail.com>
2023-09-20 11:46:19 +02:00
Philippe Scorsolini ec05d0923c
Merge pull request #551 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 6a28655
2023-09-20 09:42:39 +02:00
renovate[bot] babaf8043b
Update github/codeql-action digest to 6a28655 2023-09-19 13:07:58 +00:00
Philippe Scorsolini 6cb0b49702
refactor: switch to side effect free check
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-09-19 12:53:41 +02:00
Hasan Turken 960a14fac7
Merge pull request #535 from sttts/sttts-engine-triggered-by
controller: add TriggeredBy custom watches to engine
2023-09-19 07:21:58 +03:00
Dr. Stefan Schimanski eb74932955
controller: add TriggeredBy custom watches to engine
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-09-18 14:03:41 +03:00
Philippe Scorsolini 7a082cc2b6
fix(package parser): only drop fully commented files
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-09-15 18:12:41 +02:00
Philippe Scorsolini 2ad600c41d
Merge pull request #546 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 04daf01
2023-09-15 10:02:55 +02:00
Philippe Scorsolini 004cdff1e7
Merge pull request #547 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.58.1
2023-09-15 10:02:38 +02:00
renovate[bot] bf636b6b7e
Update module google.golang.org/grpc to v1.58.1 2023-09-14 19:24:40 +00:00
renovate[bot] 021441572c
Update github/codeql-action digest to 04daf01 2023-09-14 19:24:05 +00:00
Philippe Scorsolini 2d88794c11
Merge pull request #545 from crossplane/renovate/codecov-codecov-action-4.x 2023-09-14 18:33:26 +02:00
renovate[bot] 5ef7690a85
Update codecov/codecov-action action to v4 2023-09-14 15:55:52 +00:00
Philippe Scorsolini b55ca89e2b
Merge pull request #543 from crossplane/renovate/kubernetes-deps
Update kubernetes deps
2023-09-14 09:06:48 +02:00
Philippe Scorsolini e966c56390
Merge pull request #544 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 701f152
2023-09-14 09:06:15 +02:00
Philippe Scorsolini 30e78d8b3d
Merge pull request #542 from crossplane/renovate/docker-login-action-3.x
Update docker/login-action action to v3
2023-09-14 09:05:58 +02:00
renovate[bot] d56ab62434
Update kubernetes deps 2023-09-13 21:54:52 +00:00
renovate[bot] 59522fcbcc
Update github/codeql-action digest to 701f152 2023-09-13 17:41:23 +00:00
Hasan Turken 43c9ceeb20
Merge pull request #523 from toastwaffle/add-jitter
Add support for applying jitter when requeuing resources after reconcile
2023-09-12 15:28:05 +03:00
Philippe Scorsolini 61833984d9
Merge pull request #537 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.58.0
2023-09-12 12:24:24 +02:00
renovate[bot] 500593e03f
Update docker/login-action action to v3 2023-09-12 08:33:14 +00:00
Philippe Scorsolini ce49d22b3b reconciler: requeue without error on conflict
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-09-11 17:25:28 +02:00
Philippe Scorsolini 9d37f2639b
Merge pull request #539 from crossplane/renovate/actions-cache-digest
Update actions/cache digest to 704facf
2023-09-11 14:06:40 +02:00
renovate[bot] e8480ce83e
Update actions/cache digest to 704facf 2023-09-08 15:50:21 +00:00
Philippe Scorsolini 717fe10475
Merge pull request #536 from crossplane/renovate/golang-1.x 2023-09-08 15:09:11 +02:00
renovate[bot] 77df6103b0
Update dependency golang to v1.21.1 2023-09-08 12:15:44 +00:00
Hasan Turken e646d73c92
Merge pull request #538 from sttts/sttts-FirstNAndSomeMore
resource: add FirstNAndSomeMore helper
2023-09-08 12:57:48 +03:00
Dr. Stefan Schimanski e63d00a63c
resource: add FirstNAndSomeMore helper
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-09-08 08:28:09 +02:00
renovate[bot] 6cae9bed1e
Update module google.golang.org/grpc to v1.58.0 2023-09-06 23:01:38 +00:00
Hasan Turken a2674ee167
Merge pull request #534 from sttts/sttts-store-current-rv
pkg/resource: add StoreCurrentRV
2023-09-06 10:57:13 +03:00
Dr. Stefan Schimanski b069d9debb
pkg/resource: add StoreCurrentRV
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-09-05 22:14:06 +02:00
Samuel Littley 381948c05d Switch to supporting only a single PollIntervalHook
Signed-off-by: Samuel Littley <slittley@thoughtmachine.net>
2023-09-05 11:37:36 +01:00
Hasan Turken a7a4855626
Merge pull request #525 from crossplane/renovate/kubernetes-deps
Update kubernetes deps
2023-09-05 12:25:17 +03:00
Philippe Scorsolini 25a6c50b9f
Merge pull request #531 from crossplane/renovate/aquasecurity-trivy-action-0.x
Update aquasecurity/trivy-action action to v0.12.0
2023-09-05 09:54:03 +02:00
Philippe Scorsolini 319bf1cf66
Merge pull request #533 from crossplane/renovate/actions-checkout-4.x 2023-09-05 08:32:03 +02:00
Samuel Littley 188f2b6e21 Fix lint
Signed-off-by: Samuel Littley <slittley@thoughtmachine.net>
2023-09-04 16:53:29 +01:00
Samuel Littley b1cc110def Define WithPollJitter in terms of a PollIntervalHook
Signed-off-by: Samuel Littley <slittley@thoughtmachine.net>
2023-09-04 16:53:29 +01:00
Samuel Littley e7a425b136 Add a hook for customising the poll interval
Signed-off-by: Samuel Littley <slittley@thoughtmachine.net>
2023-09-04 16:53:29 +01:00
Samuel Littley 7bf25e3e5a Add support for applying jitter when requeuing resources after reconcile
Signed-off-by: Samuel Littley <slittley@thoughtmachine.net>
2023-09-04 16:53:29 +01:00
renovate[bot] 76d4b297dd
Update actions/checkout action to v4 2023-09-04 14:03:41 +00:00
renovate[bot] 07615592e2
Update aquasecurity/trivy-action action to v0.12.0 2023-09-02 00:50:04 +00:00
renovate[bot] e0652c1018
Update kubernetes deps 2023-08-31 19:27:25 +00:00
Philippe Scorsolini f24681a499
Merge pull request #530 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 00e563e
2023-08-31 11:08:26 +02:00
Nic Cope b34d7c1386
Merge pull request #526 from sttts/sttts-managed-reconcile-avoid-temporary-data-loss
reconciler/managed: avoid temporary data loss to managed on annotation update
2023-08-28 13:54:58 -07:00
renovate[bot] bf34bc493d
Update github/codeql-action digest to 00e563e 2023-08-28 19:45:25 +00:00
Philippe Scorsolini d4164c17c6
Merge pull request #528 from crossplane/renovate/actions-checkout-digest
Update actions/checkout digest to f43a0e5
2023-08-25 11:12:19 +02:00
Dr. Stefan Schimanski 5b4ebc1680
reconciler/managed: avoid temporary data loss to managed on annotation update
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-08-24 19:55:43 +02:00
renovate[bot] a55187e72f
Update actions/checkout digest to f43a0e5 2023-08-24 16:12:42 +00:00
Hasan Turken a597135e92
Merge pull request #475 from haarchri/feature/remove-dep-providerref
feat(remove): remove deprecated providerRef
2023-08-23 17:54:12 +03:00
Christopher Haar fd85873073 feat(remove): remove deprecated providerRef
Signed-off-by: Christopher Haar <christopher.haar@upbound.io>
2023-08-23 15:46:55 +02:00
Philippe Scorsolini 643305d3b2
Merge pull request #524 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.54.2
2023-08-21 15:25:08 +02:00
renovate[bot] 5d98e1871e
Update dependency golangci/golangci-lint to v1.54.2 2023-08-21 13:16:54 +00:00
Philippe Scorsolini 97e759ddba
Merge pull request #509 from crossplane/renovate/ubuntu-22.x
Update dependency ubuntu to v22
2023-08-21 10:23:07 +02:00
Philippe Scorsolini ad3bf67907
Merge pull request #521 from crossplane/renovate/kubernetes-deps
Update kubernetes deps
2023-08-18 12:41:45 +02:00
Philippe Scorsolini 971f3f2541
Merge pull request #507 from crossplane/renovate/golang-1.x
Update dependency golang to v1.21.0
2023-08-18 12:37:10 +02:00
Philippe Scorsolini d92a78f1fb
chore: regenerate after upgrade
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-08-18 12:19:49 +02:00
Philippe Scorsolini 0e617f8da7
Merge pull request #522 from crossplane/renovate/zeebe-io-backport-action-1.x
Update zeebe-io/backport-action action to v1.4.0
2023-08-18 12:15:32 +02:00
Philippe Scorsolini 573d2a8797
Merge pull request #519 from crossplane/renovate/golangci-golangci-lint-action-digest
Update golangci/golangci-lint-action digest to 3a91952
2023-08-18 12:14:54 +02:00
Hasan Turken fcbb2cdeb5
Merge pull request #518 from turkenh/extend-composed-type
Extend unstructured composed package with additional methods
2023-08-17 15:59:32 +03:00
renovate[bot] 42af466e5b
Update zeebe-io/backport-action action to v1.4.0 2023-08-17 10:19:21 +00:00
renovate[bot] 5a487b1ba5
Update kubernetes deps 2023-08-17 10:19:16 +00:00
renovate[bot] 31b1aa9c4c
Update dependency golang to v1.21.0 2023-08-17 10:18:40 +00:00
Philippe Scorsolini 6aee6b7c63
Merge pull request #520 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.54.1
2023-08-17 10:40:41 +02:00
Philippe Scorsolini 4cb805c64f
Merge pull request #510 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.26.1
2023-08-17 10:35:03 +02:00
renovate[bot] fbc94117c3
Update dependency golangci/golangci-lint to v1.54.1 2023-08-17 08:34:41 +00:00
Philippe Scorsolini 6bd2329427
Merge pull request #506 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to a09933a
2023-08-17 10:34:26 +02:00
renovate[bot] 54e44333ba
Update golangci/golangci-lint-action digest to 3a91952 2023-08-17 07:57:42 +00:00
Philippe Scorsolini 40f6d32a40
Merge pull request #505 from crossplane/renovate/actions-setup-go-digest
Update actions/setup-go digest to 93397be
2023-08-17 09:57:27 +02:00
renovate[bot] c19947d819
Update module github.com/bufbuild/buf to v1.26.1 2023-08-15 06:06:56 +00:00
Hasan Turken 4f3cb3d9fd
Merge pull request #513 from turkenh/remove-in-tree-vault
Remove in-tree Vault implementation
2023-08-15 09:06:07 +03:00
Hasan Turken 04ceabf588
Extend unstructured composed package with additional methods
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-08-14 19:49:08 +03:00
renovate[bot] ffeede44be
Update github/codeql-action digest to a09933a 2023-08-14 14:16:51 +00:00
Hasan Turken 8814d0ba6c
Merge pull request #512 from turkenh/pre-v1-cleanup
Cleanup deprecated code that are no longer used
2023-08-14 12:31:34 +03:00
Hasan Turken 4a83a570ec
Remove in-tree Vault implementation
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-08-14 09:34:01 +03:00
Hasan Turken 11e9468944
Cleanup deprecated stuff that are no longer used
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-08-11 13:02:54 +03:00
Philippe Scorsolini 3a49b12dfc
Merge pull request #508 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.54.0
2023-08-09 15:50:02 +02:00
renovate[bot] d266d458ab
Update dependency ubuntu to v22 2023-08-09 13:36:45 +00:00
renovate[bot] 5d7cf0d9f8
Update dependency golangci/golangci-lint to v1.54.0 2023-08-09 13:36:38 +00:00
muvaffak afbf4fc4e5
Merge pull request #504 from muvaf/parse-me-alright
pkg.parser: add the ability to parse manifests with comments
2023-08-08 18:10:03 +03:00
Muvaffak Onus 4cba0090d9 pkg.parser: add the ability to parse manifests with comments
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2023-08-08 17:55:49 +03:00
renovate[bot] e2ed6ca6d0
Update actions/setup-go digest to 93397be 2023-08-08 14:23:43 +00:00
Philippe Scorsolini 11876fa4a2
Merge pull request #503 from phisco/dev/remember-rc 2023-08-07 16:36:07 +02:00
Philippe Scorsolini 02922acfe4 docs(release): add step for empty commit and rc tag
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-08-07 16:22:31 +02:00
Philippe Scorsolini 30a148966d
Merge pull request #501 from phisco/release-md 2023-08-07 14:42:21 +02:00
Philippe Scorsolini fbb67ce577
docs: document release process
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-08-07 12:36:58 +02:00
Philippe Scorsolini 794f645d9f
Merge pull request #500 from crossplane/renovate/go-golang.org/x/net-vulnerability 2023-08-06 08:11:00 +02:00
renovate[bot] 1828285b46
Update module golang.org/x/net to v0.13.0 [SECURITY] 2023-08-06 06:00:39 +00:00
Philippe Scorsolini 3ac013d9d9
Merge pull request #498 from sttts/sttts-conflict-errors 2023-08-06 07:59:37 +02:00
Jared Watts 7e4097d530
Merge pull request #499 from crossplane/renovate/kubernetes-deps
Update module sigs.k8s.io/controller-runtime to v0.15.1
2023-08-04 19:43:29 -07:00
renovate[bot] 6ef0a90253
Update module sigs.k8s.io/controller-runtime to v0.15.1 2023-08-04 18:29:09 +00:00
Dr. Stefan Schimanski c1ae379705
reconciler/managed: only debug log transient conflict errors
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-08-04 16:32:44 +02:00
Philippe Scorsolini b689131623
Merge pull request #492 from ezgidemirel/issue-4191
Ignore k8s secret not found when ESS enabled
2023-08-04 13:42:42 +02:00
ezgidemirel c7b06073db
add unit test
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-08-04 12:44:13 +03:00
Philippe Scorsolini 89472a2578
Merge pull request #493 from haarchri/feature/controller-runtime-recover
feat(controller-runtime): enable recover true option
2023-08-04 09:49:18 +02:00
Philippe Scorsolini d863679281
Merge pull request #490 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 0ba4244
2023-08-04 09:46:22 +02:00
Jared Watts c8f7e6955b
Merge pull request #496 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.25.1
2023-08-02 17:56:23 -07:00
renovate[bot] 449ab2ee3c
Update module github.com/bufbuild/buf to v1.25.1 2023-08-02 18:28:56 +00:00
Philippe Scorsolini 9ab799e9e8
Merge pull request #495 from ezgidemirel/go-1-20
Bump go version to 1.20
2023-08-02 18:18:10 +02:00
ezgidemirel d4605406d5
Bump go version to 1.20
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-08-02 17:41:14 +03:00
Philippe Scorsolini 4475b0783b
Merge pull request #494 from crossplane/renovate/golang-1.x
Update dependency golang to v1.20.7
2023-08-02 09:38:03 +02:00
renovate[bot] 6bc74afeda
Update dependency golang to v1.20.7 2023-08-01 22:59:25 +00:00
Christopher Haar e147d407d7 feat(controller-runtime): add recover true option
Signed-off-by: Christopher Haar <christopher.haar@upbound.io>
2023-08-01 10:46:32 +02:00
Hasan Turken 8bdf48f0ea
Merge pull request #486 from crossplane/renovate/kubernetes-deps
Update kubernetes deps to v0.27.4
2023-08-01 09:56:19 +03:00
Hasan Turken ef2d8721c0
Merge pull request #484 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.25.0
2023-08-01 09:55:52 +03:00
ezgidemirel 8e756293ec
Ignore k8s secret not found when ESS enabled
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-07-31 16:59:49 +03:00
renovate[bot] a10da76cbd
Update github/codeql-action digest to 0ba4244 2023-07-28 17:27:33 +00:00
Jared Watts 0d8cbcef6f
Merge pull request #487 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 6ca1aa8
2023-07-26 19:29:23 -07:00
Jared Watts b40cee9d74
Merge pull request #488 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.57.0
2023-07-26 19:21:54 -07:00
renovate[bot] 8f63e21483
Update module google.golang.org/grpc to v1.57.0 2023-07-26 23:14:27 +00:00
renovate[bot] 46e16345c2
Update github/codeql-action digest to 6ca1aa8 2023-07-26 19:18:30 +00:00
renovate[bot] 5b02fffad0
Update kubernetes deps to v0.27.4 2023-07-20 05:13:05 +00:00
Jared Watts 8e87b2c47e
Merge pull request #485 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 1813ca7
2023-07-19 15:44:28 -07:00
renovate[bot] 053cf9af98
Update github/codeql-action digest to 1813ca7 2023-07-19 13:25:23 +00:00
renovate[bot] d0e964d8fb
Update module github.com/bufbuild/buf to v1.25.0 2023-07-18 08:27:21 +00:00
Philippe Scorsolini 5246a84c83
Merge pull request #478 from sttts/sttts-multi-error 2023-07-14 22:17:33 +02:00
Dr. Stefan Schimanski 1fadab9fda
pkg/errors: add multi error
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@upbound.io>
2023-07-14 22:06:09 +02:00
Philippe Scorsolini 27a547d7e4
Merge pull request #482 from crossplane/renovate/github-codeql-action-digest 2023-07-14 16:43:33 +02:00
Hasan Turken bb0d34b2cc
Merge pull request #456 from lsviben/granular_management_policies
Granular management policies
2023-07-14 17:41:56 +03:00
renovate[bot] 39dae97025
Update github/codeql-action digest to 489225d 2023-07-14 14:29:25 +00:00
Jared Watts 4374a3b5d1
Merge pull request #481 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.24.0
2023-07-13 19:25:23 -07:00
renovate[bot] 7fd35252eb
Update module github.com/bufbuild/buf to v1.24.0 2023-07-13 19:20:59 +00:00
Philippe Scorsolini 21b0cd6eea
Merge pull request #480 from crossplane/renovate/kubernetes-deps 2023-07-13 16:45:29 +02:00
lsviben 73a675c82c
implement granular managementPolicies
Signed-off-by: lsviben <sviben.lovro@gmail.com>
2023-07-13 13:43:34 +02:00
renovate[bot] 224e22c499
Update module sigs.k8s.io/controller-tools to v0.12.1 2023-07-13 07:58:02 +00:00
Nic Cope 8452c9b492
Merge pull request #479 from crossplane/renovate/golang-1.x
Update dependency golang to v1.20.6
2023-07-11 13:33:06 -07:00
renovate[bot] b85dcd758b
Update dependency golang to v1.20.6 2023-07-11 18:47:50 +00:00
Jared Watts c806afca12
Merge pull request #476 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 46ed16d
2023-07-07 08:19:05 +02:00
Jared Watts 6384e84a69
Merge pull request #477 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.56.2
2023-07-07 08:17:19 +02:00
renovate[bot] c5f401e964
Update module google.golang.org/grpc to v1.56.2 2023-07-06 20:07:14 +00:00
renovate[bot] 0dd0a76306
Update github/codeql-action digest to 46ed16d 2023-07-06 17:45:53 +00:00
Jared Watts a9caf72716
Merge pull request #474 from crossplane/renovate/github-codeql-action-digest
Update github/codeql-action digest to 004c5de
2023-07-03 19:47:33 +02:00
Jared Watts e9ea0025c3
Merge pull request #471 from crossplane/renovate/google.golang.org-protobuf-1.x
Update module google.golang.org/protobuf to v1.31.0
2023-07-03 18:13:50 +02:00
renovate[bot] 629092e5ab
Update github/codeql-action digest to 004c5de 2023-07-03 12:28:45 +00:00
Jared Watts 9cb5c3956c
chore: regenerate files
Signed-off-by: Jared Watts <jbw976@gmail.com>
2023-07-03 12:08:06 +02:00
Nic Cope 18594603f7
Merge pull request #473 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.23.1
2023-06-30 13:59:03 -07:00
renovate[bot] 3f7a7823fd
Update module github.com/bufbuild/buf to v1.23.1 2023-06-30 18:53:49 +00:00
Jared Watts dbb4683378
Merge pull request #472 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.23.0
2023-06-30 10:15:34 +02:00
renovate[bot] 0375e9981b
Update module github.com/bufbuild/buf to v1.23.0 2023-06-29 20:35:11 +00:00
renovate[bot] 471b2eb607
Update module google.golang.org/protobuf to v1.31.0 2023-06-26 15:09:05 +00:00
Nic Cope e979e3c19d
Merge pull request #470 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.22.0
2023-06-24 18:26:14 -07:00
renovate[bot] 30b2cd190b
Update module github.com/bufbuild/buf to v1.22.0 2023-06-23 19:57:33 +00:00
Nic Cope c52ef3ac58
Merge pull request #468 from negz/many-dependency-such-bump
Bump protoc-gen-go-grpc, mergo
2023-06-22 00:36:04 -07:00
Nic Cope 3de55a4a72 Update module github.com/imdario/mergo to v1
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-06-22 00:26:15 -07:00
Nic Cope 331f5adcfc Update module google.golang.org/grpc/cmd/protoc-gen-go-grpc to v1.3.0
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-06-22 00:25:47 -07:00
Nic Cope 1a4ff8e4f0
Merge pull request #467 from negz/more-like-athodead
Remove `pkg/test/integration`
2023-06-22 00:24:42 -07:00
Nic Cope cf0dad7772 Remove pkg/test/integration
* https://github.com/crossplane/crossplane-runtime/pull/89
* https://github.com/search?q=%22github.com%2Fcrossplane%2Fcrossplane-runtime%2Fpkg%2Ftest%2Fintegration%22&type=code

This was added in the above PR, but we never really made use of it.
Based on the above GitHub search, I think every consumer of the package
(except https://github.com/vshn/crossplane-service-broker?) are ancient,
stale forks of kubevela, oam-kubernetes-runtime, or provider-gcp. Modern
versions of these packages no longer use this one.

If we wanted to be really conservative we could mark this deprecated,
but I lean toward just removing it.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-06-21 22:06:23 -07:00
Nic Cope 2dfb8bc6bf
Merge pull request #461 from crossplane/renovate/github.com-hashicorp-vault-api-1.x
Update module github.com/hashicorp/vault/api to v1.9.2
2023-06-21 21:44:56 -07:00
Nic Cope 7be3814dd0
Merge pull request #462 from crossplane/renovate/github.com-spf13-afero-1.x
Update module github.com/spf13/afero to v1.9.5
2023-06-21 21:44:31 -07:00
renovate[bot] c0aa574fcd
Update module github.com/spf13/afero to v1.9.5 2023-06-22 04:41:28 +00:00
renovate[bot] e5bd1e4288
Update module github.com/hashicorp/vault/api to v1.9.2 2023-06-22 04:40:50 +00:00
Nic Cope e733f306e1
Merge pull request #463 from crossplane/renovate/google.golang.org-grpc-1.x
Update module google.golang.org/grpc to v1.56.1
2023-06-21 21:38:57 -07:00
Nic Cope 70c8bacd30
Merge pull request #460 from crossplane/renovate/github.com-bufbuild-buf-1.x
Update module github.com/bufbuild/buf to v1.21.0
2023-06-21 21:37:53 -07:00
Nic Cope 73b399c0e4
Merge pull request #459 from crossplane/renovate/github.com-imdario-mergo-0.x
Update module github.com/imdario/mergo to v0.3.16
2023-06-21 21:37:29 -07:00
Nic Cope 609225ee12
Merge pull request #458 from crossplane/renovate/github.com-hashicorp-go-getter-1.x
Update module github.com/hashicorp/go-getter to v1.7.1
2023-06-21 21:36:09 -07:00
renovate[bot] 26037e136c
Update module google.golang.org/grpc to v1.56.1 2023-06-22 04:33:59 +00:00
renovate[bot] 4b068184fc
Update module github.com/bufbuild/buf to v1.21.0 2023-06-22 04:32:03 +00:00
renovate[bot] c1cb801c8a
Update module github.com/imdario/mergo to v0.3.16 2023-06-22 04:31:28 +00:00
renovate[bot] 5da80dbbdc
Update module github.com/hashicorp/go-getter to v1.7.1 2023-06-22 04:30:53 +00:00
Nic Cope ad3f601f07
Merge pull request #374 from negz/reviewers
Replicate OWNERS from c/c
2023-06-21 21:25:15 -07:00
Nic Cope ecbaacb950
Merge pull request #447 from phisco/master
chore(renovate): enable all deps updates
2023-06-21 21:24:03 -07:00
Nic Cope 17eb90b6cf
Merge pull request #435 from crossplane/renovate/xt0rted-slash-command-action-2.x
Update xt0rted/slash-command-action action to v2
2023-06-21 21:23:28 -07:00
Nic Cope d9e0e7f644
Merge pull request #457 from crossplane/renovate/all-non-major-github-action
Update github/codeql-action digest to f6e388e
2023-06-21 21:23:15 -07:00
renovate[bot] a890754cb7
Update github/codeql-action digest to f6e388e 2023-06-21 13:39:35 +00:00
Hasan Turken 804e30ee2a
Merge pull request #434 from crossplane/renovate/docker-login-action-2.x
Update docker/login-action action to v2
2023-06-21 12:18:41 +03:00
Hasan Turken 29c1ef28a2
Merge pull request #452 from crossplane/renovate/all-non-major-github-action
Update all non-major github action
2023-06-19 16:47:58 +03:00
Hasan Turken f6f4784223
Merge pull request #454 from crossplane/renovate/kubernetes-deps
Update kubernetes deps to v0.27.3
2023-06-19 16:47:27 +03:00
Jared Watts 23eaff94e7
Merge pull request #455 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.53.3
2023-06-18 16:43:00 +02:00
renovate[bot] 552432007c
Update dependency golangci/golangci-lint to v1.53.3 2023-06-15 14:59:06 +00:00
renovate[bot] bdd22fde91
Update kubernetes deps to v0.27.3 2023-06-15 04:28:18 +00:00
renovate[bot] 3affa22b52
Update all non-major github action 2023-06-13 18:37:44 +00:00
Hasan Turken 2c76a4b5e8
Merge pull request #443 from aerfio/aerfio/add-get-logger-to-fake-manager
Add GetLogger method to fake.Manager
2023-06-13 12:31:41 +03:00
Hasan Turken 6eeaf0fd7e
Merge pull request #436 from crossplane/renovate/zeebe-io-backport-action-1.x
Update zeebe-io/backport-action action to v1
2023-06-13 12:31:13 +03:00
Jared Watts 98fc12c1fb
Merge pull request #451 from crossplane/renovate/all-non-major-github-action
Update all non-major github action
2023-06-09 13:08:29 +02:00
Jared Watts 346b58a730
Merge pull request #450 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.53.2
2023-06-09 13:06:08 +02:00
Mateusz Puczyński a5a6b69c4f
Add GetLogger method to fake.Manager
Signed-off-by: Mateusz Puczyński <mati6095@gmail.com>
2023-06-09 12:39:14 +02:00
renovate[bot] 42bab19863
Update dependency golangci/golangci-lint to v1.53.2 2023-06-09 06:35:17 +00:00
renovate[bot] 915481e02b
Update all non-major github action 2023-06-09 06:35:11 +00:00
Hasan Turken ec0053dda2
Merge pull request #438 from crossplane/renovate/golang-1.x
Update dependency golang to v1.20.5
2023-06-09 09:34:53 +03:00
Hasan Turken 535008d07c
Merge pull request #445 from crossplane/renovate/kubernetes-deps
Update module sigs.k8s.io/controller-tools to v0.12.0
2023-06-09 09:31:12 +03:00
renovate[bot] 409b0157b9
Update zeebe-io/backport-action action to v1 2023-06-08 16:48:56 +00:00
renovate[bot] d4b34da4e3
Update docker/login-action action to v2 2023-06-07 17:29:14 +00:00
renovate[bot] ee2f0e7732
Update dependency golang to v1.20.5 2023-06-06 18:20:00 +00:00
renovate[bot] cf49987bb2
Update module sigs.k8s.io/controller-tools to v0.12.0 2023-06-02 09:17:41 +00:00
Hasan Turken 025f5287ee
Merge pull request #449 from phisco/bump-bufbuildbuf
chore: bump github.com/bufbuild/buf
2023-06-02 12:16:47 +03:00
Philippe Scorsolini 767b052735
chore: bump github.com/bufbuild/buf
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-06-01 11:04:47 +02:00
Philippe Scorsolini 6572f9f1f0
chore: enable all deps updates
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-05-31 16:34:35 +02:00
Jared Watts 85710e3571
Merge pull request #444 from crossplane/renovate/all-non-major-github-action
Update all non-major github action
2023-05-30 12:48:29 +02:00
Hasan Turken f0f7368406
Merge pull request #441 from aerfio/aerfio/bump-controller-runtime
Bump sigs.k8s.io/controller-runtime to v0.15.0
2023-05-30 12:49:59 +03:00
renovate[bot] b14b5f02b5
Update all non-major github action 2023-05-29 21:47:31 +00:00
Daniel Mangum 3486cbbcd5
Merge pull request #442 from phisco/renovate-single-group-kubernetes-deps
chore: configure single group for all kubernetes related prs
2023-05-29 17:47:06 -04:00
Mateusz Puczyński 920e5b1ac6
bump sigs.k8s.io/controller-runtime to v0.15.0
Signed-off-by: Mateusz Puczyński <mati6095@gmail.com>
2023-05-26 17:29:45 +02:00
Philippe Scorsolini b31c378797
chore: configure single group for all kubernetes related prs
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-05-26 17:24:10 +02:00
Jared Watts 1316ae6695
Merge pull request #437 from crossplane/renovate/all-non-major-github-action
Update github/codeql-action digest to 29b1f65
2023-05-08 17:21:19 +02:00
renovate[bot] 6671931d6c
Update github/codeql-action digest to 29b1f65 2023-05-04 20:55:25 +00:00
Hasan Turken e754703fd3
Merge pull request #429 from crossplane/renovate/actions-checkout-3.x
Update actions/checkout action to v3
2023-05-04 13:07:28 +03:00
muvaffak 492ad7c635
Merge pull request #432 from crossplane/renovate/all-non-major-github-action
Update all non-major github action
2023-04-20 23:48:53 +03:00
renovate[bot] 26cd8d78ab
Update all non-major github action 2023-04-20 20:13:37 +00:00
renovate[bot] 8b5cbb9b47
Update xt0rted/slash-command-action action to v2 2023-04-13 22:29:29 +00:00
muvaffak c8cff1a7fb
Merge pull request #431 from crossplane/renovate/actions-setup-go-4.x
Update actions/setup-go action to v4
2023-04-13 20:41:55 +03:00
muvaffak faaaad795b
Merge pull request #430 from crossplane/renovate/actions-github-script-6.x
Update actions/github-script action to v6
2023-04-13 20:41:25 +03:00
renovate[bot] 5d4bb614d6
Update actions/checkout action to v3 2023-04-13 17:40:41 +00:00
muvaffak ecdefb1c06
Merge pull request #427 from crossplane/renovate/golang-1.x
Update dependency golang to v1.20.3
2023-04-13 20:40:39 +03:00
muvaffak 7d3345b3d4
Merge pull request #424 from crossplane/renovate/all-non-major-github-action
Update all non-major github action
2023-04-13 20:40:14 +03:00
Philippe Scorsolini 1faa4ffdef chore: remove version, ignored from 0.0.6
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-04-06 21:40:58 +02:00
renovate[bot] 8edc7e3e7c
Update all non-major github action 2023-04-06 19:36:47 +00:00
renovate[bot] 0ee9ae6d48
Update actions/setup-go action to v4 2023-04-06 18:41:17 +00:00
Hasan Turken 4e1673b714
Merge pull request #417 from turkenh/ignore-create-annotaions
Filter out external create annotations from Desired State
2023-04-06 18:57:02 +03:00
Hasan Turken 8ad78a7b31
Avoid using reflect.DeepEqual in annotationsChangedPredicate
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-04-06 18:50:01 +03:00
renovate[bot] 24c5c524c3
Update actions/github-script action to v6 2023-04-06 15:21:59 +00:00
Hasan Turken 2f68049451
Merge pull request #428 from phisco/renovate/group-digests-too
chore(renovate): group also actions' digest
2023-04-06 18:21:35 +03:00
Philippe Scorsolini 308868bbfa
chore(renovate): group also actions' digest
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-04-06 10:13:30 +02:00
renovate[bot] 5a5f747b6b
Update dependency golang to v1.20.3 2023-04-05 12:23:12 +00:00
Hasan Turken 4022b370e3
Merge pull request #425 from crossplane/renovate/golangci-golangci-lint-1.x
Update dependency golangci/golangci-lint to v1.52.2
2023-04-05 15:22:52 +03:00
Philippe Scorsolini 511b39fa56
chore: address issues reported by revive
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-04-05 12:03:27 +02:00
renovate[bot] a851dacc64
Update dependency golangci/golangci-lint to v1.52.2 2023-04-01 17:51:56 +00:00
Jared Watts 21c67ec1da
Merge pull request #422 from crossplane/renovate/golang-1.x
Update dependency golang to v1.20.2
2023-04-01 10:50:59 -07:00
Jared Watts d2c913da94
Merge pull request #423 from crossplane/renovate/kubernetes-patches
Update kubernetes patches
2023-04-01 10:49:57 -07:00
renovate[bot] ae604ce5fb
Update kubernetes patches 2023-04-01 01:44:54 +00:00
renovate[bot] 867bfa42f3
Update dependency golang to v1.20.2 2023-03-31 19:39:40 +00:00
Hasan Turken ae5aed273c
Merge pull request #410 from crossplane/renovate/go-github.com/hashicorp/go-getter-vulnerability
Update module github.com/hashicorp/go-getter to v1.7.0 [SECURITY]
2023-03-31 16:35:42 +03:00
renovate[bot] 05ce93de71
Update module github.com/hashicorp/go-getter to v1.7.0 [SECURITY] 2023-03-31 13:27:58 +00:00
Hasan Turken 661a4d7b8c
Merge pull request #411 from crossplane/renovate/go-github.com/moby/buildkit-vulnerability
Update module github.com/moby/buildkit to v0.11.4 [SECURITY]
2023-03-31 16:26:46 +03:00
Hasan Turken 64907fd946
Merge pull request #408 from crossplane/renovate/go-github.com/containerd/containerd-vulnerability
Update module github.com/containerd/containerd to v1.6.18 [SECURITY]
2023-03-31 16:25:36 +03:00
Hasan Turken 2af304be78
Merge pull request #414 from crossplane/renovate/pin-dependencies
Pin dependencies
2023-03-31 16:24:52 +03:00
Hasan Turken bc8be4cd89
Merge pull request #416 from ezgidemirel/deprecate-vault
Deprecate in-tree Vault
2023-03-30 11:13:44 +03:00
ezgidemirel 30ed28af9f
Deprecate in-tree Vault
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-30 11:03:09 +03:00
Hasan Turken 9bb1416205
Filter out external create annotations from DesiredState
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-29 17:03:14 +03:00
Hasan Turken 38469396cb
Merge pull request #415 from phisco/imports-sorting
chore(linter): switching from goimports to gci enforcing imports sorting
2023-03-29 10:34:48 +03:00
Philippe Scorsolini 57dafafdaf
chore(linter): switching from goimports to gci enforcing imports sorting
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-29 09:23:07 +02:00
Hasan Turken 931018136d
Merge pull request #384 from turkenh/o_o
Observe Only Management Policy Support
2023-03-27 12:23:11 +03:00
Hasan Turken 0dd35672f2
Pin design doc section for deprecation of deletion policy
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-27 12:08:35 +03:00
Hasan Turken 0023964825
Resolve Comments in Observe Only PR
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-27 12:05:07 +03:00
Hasan Turken 473dc1e87a
Management Policies should be off by default
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-27 12:05:07 +03:00
Hasan Turken 743b93ca70
Do not late init when observe only
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-27 12:05:07 +03:00
Hasan Turken 2f4e4c0d9d
Lateinit and publish conn for observe only
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-27 12:05:06 +03:00
Hasan Turken 79cb4c8ac1
Add management policy to managed
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-27 12:05:06 +03:00
Hasan Turken 2bc6c4e5ee
Merge pull request #403 from phisco/trivy-scan-ci
ci: add trivy scan in ci workflow
2023-03-27 11:41:26 +03:00
Philippe Scorsolini d68c678f01 ci: exit code 1 if trivy finds vulnerabilities
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-27 10:32:55 +02:00
Philippe Scorsolini e620c208f2 ci: add trivy scan in ci workflow
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-27 10:32:55 +02:00
renovate[bot] 35adf614c8
Pin dependencies 2023-03-27 08:31:48 +00:00
Hasan Turken 5d3027589a
Merge pull request #388 from crossplane/dependabot/go_modules/golang.org/x/net-0.7.0
Bump golang.org/x/net from 0.4.0 to 0.7.0
2023-03-27 11:30:09 +03:00
renovate[bot] 4857a1618f
Update module github.com/moby/buildkit to v0.11.4 [SECURITY] 2023-03-27 07:50:09 +00:00
renovate[bot] 7a99280609
Update module github.com/containerd/containerd to v1.6.18 [SECURITY] 2023-03-27 07:49:10 +00:00
Hasan Turken cdae82e6e5
Merge pull request #402 from phisco/renovate/configure
renovate: configuration
2023-03-27 10:47:02 +03:00
Philippe Scorsolini 57bb5893ec
chore(renovate): move to custom renovate config
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-25 12:42:53 +01:00
renovate[bot] f051e1f64a
Add renovate.json 2023-03-24 03:43:27 +00:00
Hasan Turken cf3c7a0962
Merge pull request #406 from ezgidemirel/tlsconfig
Add secret name to ESSOptions
2023-03-22 18:09:43 +03:00
ezgidemirel 00a8da972a
Add secret name to ESSOptions
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 18:01:48 +03:00
dependabot[bot] 79726873b1
Bump golang.org/x/net from 0.4.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.4.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.4.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-22 14:26:29 +00:00
Hasan Turken 9c8fcc0c26
Merge pull request #379 from ezgidemirel/ess
External Secret Store API and Client Implementation
2023-03-22 17:25:06 +03:00
ezgidemirel 76fec039fb
simplified LoadMTLSConfig signature
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 17:18:33 +03:00
ezgidemirel 72e474ea27
rename test certificate folder
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:06 +03:00
ezgidemirel b0785ed1ca
change store type, make tls config an option
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:06 +03:00
ezgidemirel 6d770a1106
remove unused messages from proto file
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:06 +03:00
ezgidemirel 7a2ca31e32
fix loaded CA certs
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:06 +03:00
ezgidemirel fc63b94eb5
Remove certificate loading to make it on upper layers, add unit tests
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:06 +03:00
ezgidemirel bbb004932c
Implement gRPC client
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:05 +03:00
ezgidemirel 80e0b0c662
Extend secret store API with "External" type
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:05 +03:00
ezgidemirel a1c142b7c6
Add External Secret Store proto files
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2023-03-22 13:00:04 +03:00
Hasan Turken caacf09d8a
Merge pull request #400 from negz/bump-bump
Bump GitHub workflows and build submodule
2023-03-22 12:58:23 +03:00
Hasan Turken 112e9eda45
Add nolint directive for musttag on types used in unit tests
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-22 12:52:52 +03:00
Nic Cope e8004abee1
Bump build
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-03-22 12:42:33 +03:00
Nic Cope 5d9c550aed
Bump versions in .github workflow
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-03-22 12:42:33 +03:00
Hasan Turken c424c4aca5
Merge pull request #372 from turkenh/predicate-desired-state-changed
Add DesiredStateChanged to Filter out Updates on Status
2023-03-20 17:30:10 +03:00
Jared Watts 291e6084b2
Merge pull request #396 from R3DRUN3/master
Add add CI and latest release badges
2023-03-17 19:51:40 -07:00
Hasan Turken 3008beba94
Deprecate PredicateFn and helper predicate functions
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-17 17:27:56 +03:00
Hasan Turken c4ec21474a
Add DesiredStateChanged to filter out updates going to status
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-03-17 17:27:56 +03:00
Hasan Turken dae68b74df
Merge pull request #398 from AdamKorcz/fuzzing
fuzzing: fix broken OSS-Fuzz build
2023-03-17 16:10:56 +03:00
AdamKorcz 584136662c fuzzing: fix broken OSS-Fuzz build
Signed-off-by: AdamKorcz <adam@adalogics.com>
2023-03-17 12:43:08 +00:00
Hasan Turken d72721e2b9
Merge pull request #397 from phisco/fuzz-parse-separate-file
tests: move FuzzParse to separate file
2023-03-17 12:48:11 +03:00
Philippe Scorsolini d95d8e0cca tests: move FuzzParse to separate file
Co-authored-by: Lovro Sviben <46844730+lsviben@users.noreply.github.com>
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-16 22:26:08 +01:00
Hasan Turken e0b2108c51
Merge pull request #394 from phisco/dev/fuzz-parse
tests(fuzz): add FuzzParse test case
2023-03-16 12:00:08 +03:00
r3drun3 8bb5736172
docs(readme): add add CI and latest release badges
Signed-off-by: r3drun3 <simone.ragonesi@kiratech.it>
2023-03-16 09:04:08 +01:00
Philippe Scorsolini 53a78a1962
tests(fuzz): copy fuzz build script over from crossplane/crossplane
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-13 13:11:31 +01:00
Philippe Scorsolini 5a5939990b
tests(fuzz): add FuzzParse test case
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-13 11:26:30 +01:00
Hasan Turken 043aa3283a
Merge pull request #389 from phisco/dev/fix-max-index
fix: properly validate max index
2023-03-08 18:17:12 +03:00
Philippe Scorsolini 0aac4ba546
fix: properly validate max index
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-08 16:10:26 +01:00
Hasan Turken 53508a9f43
Merge pull request from GHSA-vfvj-3m3g-m532
fix: enforce max index value for paths
2023-03-08 16:44:59 +03:00
Philippe Scorsolini 7560fbc041 fix: enforce max index value for paths
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-03-08 14:41:11 +01:00
Jared Watts a47015271b
Merge pull request #387 from plumbis/master
Update link to contributing guide
2023-03-03 14:25:52 -08:00
Pete Lumbis f61206bb0a
update contrib guide link to c/c repo
Signed-off-by: Pete Lumbis <pete@upbound.io>
2023-03-03 15:46:20 -05:00
Nic Cope 934f64e57e
Merge pull request #378 from phisco/dev/secretstoretype-enum-validation
fix: add missing secretStoreType validation annotation
2023-02-28 17:41:06 -08:00
Hasan Turken af9e3effae
Merge pull request #367 from eljohnson92/support_float_pointers
add support for float pointer references
2023-02-28 15:21:31 +03:00
Hasan Turken d6c8b29a6f
Merge pull request #380 from turkenh/fix-secret-owner
Fix connection secret owner check for K8s Secret Store
2023-02-20 16:52:27 +03:00
Hasan Turken 99021e56bd
Merge pull request #371 from phisco/dev/security-md
Add SECURITY.md
2023-02-20 12:19:57 +03:00
Hasan Turken b13075274f
Fix connection secret owner check for K8s Secret Store
Fixes https://github.com/crossplane/crossplane/issues/3520

Signed-off-by: Hasan Turken <turkenh@gmail.com>
2023-02-09 18:18:17 +03:00
Philippe Scorsolini d8a21d394b
fix: add missing validation annotation
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-01-30 10:58:03 +01:00
Nic Cope 1fc35a41fc
Merge pull request #377 from negz/many-bump
Empty commit to move master past release-1.9
2023-01-25 14:32:01 -08:00
Nic Cope 2e56264a04 Empty commit to move master past release-1.9
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 14:23:33 -08:00
Nic Cope a8605b76a8
Merge pull request #375 from negz/many-bump
Bump Kubernetes dependencies (and CI workflow) to latest
2023-01-25 10:41:42 -08:00
Nic Cope 9e69576057 Add a test for the new subresource Create method
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:38 -08:00
Nic Cope 695583547b Bump controller-runtime to v0.14.1
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:38 -08:00
Nic Cope fd0a07f8eb Remove //nolint:interfacer directive
This linter has been deprecated and is disabled. I would have thought
nolintlint would catch this, but it did not.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:38 -08:00
Nic Cope b099031ba0 Pass GetOptions through to wrapped client
Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:38 -08:00
Nic Cope 71190c3e9a Remove fake.MockStatus* type aliases
I thought this would help with compatibility, but unfortunately this
package has breaking changes that will affect anyone who was using these
types regardless.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:38 -08:00
Nic Cope 72a7dd0e0f Replicate CI workflow from c/c
This also removes a few jobs that are no-ops on this repo, including e2e
tests and artifact publishing. Probably better not to imply that we're
doing these things when we aren't.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:38 -08:00
Nic Cope 8b832430e9 Bump Kubernetes dependencies
This required some updates to our implementations of client.Client,
which now has a generic SubResource sub-client.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:34:37 -08:00
Nic Cope f0fcbc0af5 Update linter config to match c/c
This repo is a little out of date relative to our latest linting
practices.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-25 10:32:46 -08:00
Nic Cope 73d9760d19
Merge pull request #369 from crossplane/dependabot/go_modules/github.com/aws/aws-sdk-go-1.33.0
Bump github.com/aws/aws-sdk-go from 1.15.78 to 1.33.0
2023-01-25 10:31:39 -08:00
Nic Cope b093ecf71e
Merge pull request #333 from crossplane/dependabot/go_modules/github.com/hashicorp/go-getter-1.6.1
Bump github.com/hashicorp/go-getter from 1.4.0 to 1.6.1
2023-01-25 10:31:15 -08:00
Nic Cope f27b2e1a81 Replicate OWNERS from c/c
I'd like to setup automatic PR assignment (with reviewers) on this repo.
In practice I think maintainers and reviewers here are still fairly 1:1
with core Crossplane folks.

Signed-off-by: Nic Cope <nicc@rk0n.org>
2023-01-24 09:17:39 -08:00
Philippe Scorsolini aaa5b0d172
Add SECURITY.md
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
2023-01-23 12:45:44 +01:00
dependabot[bot] cdc057b654
Bump github.com/aws/aws-sdk-go from 1.15.78 to 1.33.0
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.15.78 to 1.33.0.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/v1.33.0/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.15.78...v1.33.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-12 23:59:02 +00:00
dependabot[bot] a876c068b8
Bump github.com/hashicorp/go-getter from 1.4.0 to 1.6.1
Bumps [github.com/hashicorp/go-getter](https://github.com/hashicorp/go-getter) from 1.4.0 to 1.6.1.
- [Release notes](https://github.com/hashicorp/go-getter/releases)
- [Changelog](https://github.com/hashicorp/go-getter/blob/main/.goreleaser.yml)
- [Commits](https://github.com/hashicorp/go-getter/compare/v1.4.0...v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-getter
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-12 23:58:47 +00:00
Nic Cope 6d423d5111
Merge pull request #327 from turkenh/update-vault-deps
Bump Hashicorp dependencies to latest
2023-01-12 10:43:32 -08:00
Daniel Mangum 1e119b5d0a
Merge pull request #368 from AlainRoy/patch-1
Fix broken link to developer guide
2022-12-20 19:00:43 -05:00
Alain Roy 34a54bd850
Fix broken link to developer guide
Signed-off-by: Alain Roy <alain@upbound.io>
2022-12-20 15:59:08 -08:00
Evan Johnson ce686bf20e add support for float pointer references
Signed-off-by: Evan Johnson <eljohn1014@gmail.com>
2022-12-08 12:29:11 -05:00
Nic Cope 65044f0439
Merge pull request #364 from ezgidemirel/comp-rev-selector
Add composition revision selectors
2022-11-14 11:51:50 -08:00
Nic Cope 3453dc5d27
Merge pull request #365 from MisterMX/fix/SetEnvironmentConfigReferences
fix(composite): SetEnvironmentConfigReferences to correct path
2022-11-09 12:50:52 -08:00
Maximilian Blatt 39428e10f6 fix(composite): SetEnvironmentConfigReferences to correct path
Signed-off-by: Maximilian Blatt <maximilian.blatt-extern@deutschebahn.com>
(external expert on behalf of DB Netz AG)
2022-11-09 00:27:13 +01:00
ezgidemirel efc8702e31
Add composition revision selectors
Signed-off-by: ezgidemirel <ezgidemirel91@gmail.com>
2022-11-03 14:41:45 +03:00
muvaffak fa5545f26b
Merge pull request #361 from ulucinar/fix-cncf-fuzzing
Add omitempty json tag to fake.ConnectionDetailsLastPublishedTimer.Time field
2022-10-20 10:19:48 +03:00
Alper Rifat Ulucinar 31279534ed
Add omitempty json tag to fake.ConnectionDetailsLastPublishedTimer.Time field
Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2022-10-19 23:46:07 +03:00
Nic Cope bce61005a1
Merge pull request #355 from nokia/respect_finalizers
Support foreground cascading deletion
2022-10-11 18:39:34 -07:00
Bob Haddleton da77f4e104 Add blockOwnerDeletion: true and compositeDeletePolicy
Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>
2022-10-11 09:35:04 -05:00
muvaffak 84e629b958
Merge pull request #357 from ulucinar/fix-351
Add support for a pause annotation which pauses reconciliations on managed resources
2022-09-30 10:32:09 +03:00
Alper Rifat Ulucinar eaa6119f23
Add meta.IsPaused that checks whether reconciliations are paused for the managed resource
Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2022-09-30 01:24:50 +03:00
Alper Rifat Ulucinar d5661c8fd6
Add support for a pause annotation which pauses reconciliations on managed resources
- If a managed resource has the "crossplane.io/paused" annotation with its value
  set to "true", then the managed reconciler emits an event indicating that
  further reconciliations on that resource are paused and returns early after
  setting a Synced status condition to false with the reason "ReconcilePaused".

Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2022-09-29 04:27:29 +03:00
Nic Cope 619edbacb8
Merge pull request #353 from MisterMX/composite-environment
feat(composite):  Add support for EnvironmentConfigs
2022-09-07 10:28:48 -07:00
Maximilian Blatt dfd468741d feat(composite): Add support for EnvironmentConfigs
Signed-off-by: Maximilian Blatt <maximilian.blatt-extern@deutschebahn.com>
(external expert on behalf of DB Netz AG)
2022-09-05 22:27:26 +02:00
muvaffak d9c25ae277
Merge pull request #344 from muvaf/i-am-gone
fieldpath: add `DeleteField` function to delete elements from Paved
2022-08-09 10:38:54 +03:00
Muvaffak Onus ba9d8c29a7 fieldpath: DeleteField should be no-op if it cannot reach the node and it should be able to delete a top-level field
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-08-05 19:39:20 +03:00
Muvaffak Onus 778f16318e github: golangci should have a specific patch version, otherwise it enables unexpected linters
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-08-05 16:37:02 +03:00
Muvaffak Onus d950363569 fieldpath: add DeleteField function to delete elements from Paved
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-08-05 14:29:14 +03:00
muvaffak 9ea84ae536
Merge pull request #342 from epk/epk/go1-18
Upgrade to Go 1.18
2022-07-22 19:25:06 +03:00
Aditya Sharma cd68866501 Fix lints
Signed-off-by: Aditya Sharma <git@adi.run>
2022-07-21 22:01:32 -07:00
Aditya Sharma 1deb753676 s/interface{}/any/g
Signed-off-by: Aditya Sharma <git@adi.run>
2022-07-21 21:46:18 -07:00
Aditya Sharma 2fc4f2cd51 gofmt -s -l -w .
Signed-off-by: Aditya Sharma <git@adi.run>
2022-07-21 21:46:08 -07:00
Aditya Sharma 8a8f1dbb7d Upgrade to Go 1.18
Signed-off-by: Aditya Sharma <git@adi.run>
2022-07-21 21:44:49 -07:00
Nic Cope 575cf07caf
Merge pull request #339 from negz/emptiness
Empty commit to move master past release-0.17
2022-07-13 14:27:59 -07:00
Nic Cope 0c2d97421d Empty commit to move master past release-0.17
Signed-off-by: Nic Cope <nicc@rk0n.org>
2022-07-13 14:24:28 -07:00
Nic Cope aca738a12a
Merge pull request #338 from avalanche123/increase-burst
increase QPS and burst
2022-07-13 14:06:57 -07:00
Bulat Shakirzyanov fa6b2ef1e2 bump up the limits
Signed-off-by: Bulat Shakirzyanov <83289+avalanche123@users.noreply.github.com>
2022-07-13 11:58:52 -04:00
Bulat Shakirzyanov b781506537 increase burst to rps * 3
Signed-off-by: Bulat Shakirzyanov <83289+avalanche123@users.noreply.github.com>
2022-07-12 10:03:41 -04:00
muvaffak a520b60f16
Merge pull request #334 from sergenyalcin/fix-policy-enums
Add "IfNotPresent" to ResolvePolicy enum
2022-06-16 14:54:00 +03:00
Sergen Yalçın 23dad77b17
Add "IfNotPresent" to ResolvePolicy enum
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-06-16 13:48:01 +03:00
muvaffak 75dda897e5
Merge pull request #328 from sergenyalcin/fix-circular-reference
Support for having circular dependencies while using referencers
2022-06-13 18:27:11 +03:00
Sergen Yalçın afe248692b
Use kubebuilder enum for new policy fields
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-06-13 18:11:54 +03:00
Sergen Yalçın 5770f19db9
Add unit test cases
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-06-01 11:33:11 +03:00
Sergen Yalçın 38e79f4960
Preserve order of reference resolution
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-05-30 18:48:30 +03:00
Jared Watts edc27bfc3e
Merge pull request #332 from jbw976/empty-for-v0.16.0
Empty commit for the v0.16.0 release
2022-05-17 15:43:15 +02:00
Jared Watts 95e98e4c0e
Empty commit for the v0.16.0 release
Signed-off-by: Jared Watts <jbw976@gmail.com>
2022-05-17 15:29:18 +02:00
Sergen Yalçın e2fb202fd5
Add policy api for Selector
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-05-12 16:11:37 +03:00
Sergen Yalçın 66e5e7ad0b
Re-design the Policy API
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-04-25 18:14:52 +03:00
muvaffak onuş 0e8935d6d9
Merge pull request #326 from muvaf/webhook-chains
Add validator and mutator chain executors to be used by provider webhooks
2022-04-22 01:53:08 +03:00
Muvaffak Onus 85f12b9e2c
webhook.mutator: add unit tests
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-04-22 01:49:49 +03:00
muvaffak onuş 85ab1c2780
Merge pull request #329 from muvaf/hasan
owners: add turkenh as maintainer
2022-04-21 01:45:26 +03:00
Muvaffak Onus 4f95cc7643
owners: add turkenh as maintainer since he is a maintainer in crossplane
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-04-19 23:15:15 +03:00
Sergen Yalçın ec82fef853
Add a new policy about resolving references for every reconcile loop
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-04-16 16:03:18 +03:00
Sergen Yalçın ac7cf2045e
Support for having circular dependencies while using referencers
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
2022-04-14 14:56:17 +03:00
Hasan Turken 50565fbf7d
Bump Hashicorps deps to latest
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-04-08 00:29:07 +03:00
Muvaffak Onus 43f716a1d4
webhook.validator: add unit tests
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-04-07 00:36:00 +03:00
Muvaffak Onus f655302042
webhook.validator: add options to the initializer
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-04-07 00:25:48 +03:00
Muvaffak Onus 0b23ec1338
webhook: add mutator struct for chained execution of mutating webhook functions
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-04-07 00:21:48 +03:00
Muvaffak Onus cdc7266d4b
webhook: add validator struct for chained execution of validation webhook functions
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-04-06 01:21:33 +03:00
muvaffak onuş 988c9ba9c2
Merge pull request #325 from turkenh/ess-fixes 2022-03-15 17:14:14 +03:00
Hasan Turken 79ea2fe449
Add comment for linter and use types.UID for uid parameter
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-15 10:29:23 +03:00
Hasan Turken 754abc4f83
Separate Vault KV client for v1 and v2
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-13 14:08:59 +03:00
Hasan Turken 6f9579f9bd
Use string instead if interface for KVSecret data
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-12 23:25:29 +03:00
Hasan Turken 80debfade8
Fix owner not being set for delete
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-11 22:34:48 +03:00
muvaffak onuş 6966b5a68a
Merge pull request #323 from turkenh/ess-composition
External Secret Support in Composition Types
2022-03-11 15:43:23 +03:00
Hasan Turken d7cb4e66da
Fix metadata handling with Vault v1
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-11 12:00:52 +03:00
Hasan Turken ff57cdc7c4
Ensure secret owned by object before delete
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-11 10:29:34 +03:00
Hasan Turken ee3fb975d2
Fix writeOption conversion and add unit tests
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-11 01:16:06 +03:00
Hasan Turken 2d3b3def00
Add metadata support for Vault kv v1
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-10 23:45:40 +03:00
Hasan Turken 86fb15da2c
Extend Secret Store interface with more power
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-10 18:10:52 +03:00
Hasan Turken 867c9bb8e8
Track connection secret owner with label
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-10 09:56:04 +03:00
Hasan Turken acaeae2f15
Add more unit tests for Connection Details Manager
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 17:25:15 +03:00
Hasan Turken bbbe8f8c66
Return proper error if Secret Store disabled but API used
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 16:29:42 +03:00
Hasan Turken 5273c0ff6d
Move features package to individual repos
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 14:56:39 +03:00
Hasan Turken 2f224692a9
Use store.KeyValue in connection.store package
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 14:46:59 +03:00
Hasan Turken c8cc06c5fb
Implement ConnectionPropagator in connection.DetailsManager
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 12:43:53 +03:00
Hasan Turken 60059a2241
Add PublishConnectionDetailsTo to Composition types
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 12:43:53 +03:00
Hasan Turken c55240a2a2
Add PublishConnectionDetailsTo to Managed resource spec
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 12:43:52 +03:00
Hasan Turken b19ffddf2f
Move features package to runtime
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 12:43:52 +03:00
Hasan Turken 3ce0d92570
Refactor packages for connection details types and interfaces
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 12:43:52 +03:00
Hasan Turken e0edbc592f
Define types for using ESS with composition
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-09 12:43:52 +03:00
muvaffak onuş b35cdabfbe
Merge pull request #324 from muvaf/parser-or
package.parser: make Or linter work with arbitrary number of linters
2022-03-09 11:26:36 +03:00
Muvaffak Onus 90b7988df4
parser.linter: use strings.Join instead of strings.TrimSuffix to make the flow simpler
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-03-09 11:21:56 +03:00
Nic Cope 1bb01bda7f
Merge pull request #322 from turkenh/ess-vault
Add Vault as an External Secret Store
2022-03-08 15:14:43 -08:00
Hasan Turken d591b5e442
Vault ESS - resolve comments and add support for custom CA bundle
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-07 23:47:37 +03:00
Muvaffak Onus 155dc9d659
package.parser: make Or linter work with arbitrary number of linters instead of only two
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-03-07 17:00:48 +03:00
Hasan Turken 71c2ae8a54
Add unit tests for Vault Secret Store
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:04 +03:00
Hasan Turken df72fd3089
Add unit tests for Vault KV client
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:04 +03:00
Hasan Turken 551b414fc8
Use metadata API with scheme
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:04 +03:00
Hasan Turken ba2ece4762
Extend KV client for v2 engine
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:04 +03:00
Hasan Turken 796c2ec38e
Implement client for KV Secrets API
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:04 +03:00
Hasan Turken ac03ae3946
Add initial implementation Vault as Secret Store
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:04 +03:00
Hasan Turken ae55806eb4
Add token auth config to api
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 21:00:03 +03:00
Nic Cope 3232ffa5ef
Merge pull request #321 from turkenh/ess-foundation
Add connection package for External Secret Store support
2022-03-02 09:08:05 -08:00
Hasan Turken 31cce62ecf
Mark connection secret metadata fields as optional
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 09:20:08 +03:00
Hasan Turken 1d36dd39ba
More unit tests for kubernetes package
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-02 00:34:59 +03:00
Hasan Turken 06c155d60b
Define scheme for connection secret metadata
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-03-01 14:20:15 +03:00
Hasan Turken 15cf494997
Simplify kubernetes client by reusing clientcmd method
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-25 21:31:08 +03:00
Hasan Turken 21f1473d10
Fix optional fields in connection details API
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-25 17:55:36 +03:00
Hasan Turken 3215c89454
Add unit tests for Kubernetes secret store
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-18 21:55:32 +03:00
Hasan Turken cfcec11142
Do not use unstructured client for StoreConfig
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-17 23:29:03 +03:00
Hasan Turken 258add4288
Resolve first pass of comments in ESS foundation
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-17 16:28:52 +03:00
Hasan Turken 88c4d273a5
Remove publishConnectionDetailsTo from managed resource spec
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-16 11:32:34 +03:00
Hasan Turken a31600daa8
Do not unmarshal if no metadata provided
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-16 10:10:08 +03:00
Hasan Turken 9e13a889fe
Add unit tests for connection manager
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-16 00:00:51 +03:00
Hasan Turken 3c908b7855
Refactor naming and package structure
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-15 17:08:28 +03:00
Hasan Turken 48f7c046f5
Fix namespace calculation for secrets
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-10 19:19:52 +03:00
Hasan Turken bc23452656
Use seperate interfaces to keep existing MRs compiling
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-10 16:34:29 +03:00
Hasan Turken 936e12174d
Add fake store for unit tests
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-10 15:50:45 +03:00
Hasan Turken 19034f22d1
Fetch secret store config and complete connection manager
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-10 00:27:55 +03:00
Hasan Turken 31c8287de6
Remove reviewable and check-diff from Makefile
- To fix overriding target warnings in make output logs
- In favor of the ones in build submodule

Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-10 00:22:33 +03:00
Hasan Turken 8cc6436606
Add connection secret manager
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-08 18:25:32 +03:00
Hasan Turken cb4062f9c3
Add a placeholder Vault secret store
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-08 18:24:10 +03:00
Hasan Turken 05fff0ec25
Add kubernetes secret store
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-08 18:21:19 +03:00
Hasan Turken 300dc3127f
Define secret store interface
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-08 18:20:47 +03:00
Hasan Turken 4b082d3585
Extend managed resource with new API
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-08 18:19:57 +03:00
Hasan Turken 28d33bf0db
Add initial types for External Secret Store
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2022-02-08 18:18:43 +03:00
muvaffak onuş 428b7c3903
Merge pull request #308 from muvaf/upd-go
Update Go to 1.17 and k8s libraries to 1.23
2022-01-06 17:01:06 +03:00
Muvaffak Onus 2c8369b865
update k8s libraries to latest
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-01-06 16:50:45 +03:00
Muvaffak Onus 65392c8c35
add changes coming with go 1.17
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-01-06 16:49:33 +03:00
Muvaffak Onus 5452374109
update go to v1.17.5
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2022-01-06 16:44:15 +03:00
Nic Cope d43d510ec5
Merge pull request #306 from negz/dc
Tweak ExternalDisconnecter implementation
2021-12-02 15:09:00 -08:00
Nic Cope 295de4764e Tweak ExternalDisconnecter implementation
The primary functional change here is to avoid setting a status condition when a
deferred disconnect fails. We don't want to overwrite the original status
condition that may have been written if we're returning from Reconcile because
we hit an error. Emitting an event and a debug log should be sufficient.

This commit also tweaks a bit of grammar and updates the NopConnectDisconnecter
implementation to more closely match its docstring description.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-12-02 22:37:02 +00:00
Nic Cope 5cc9857410
Merge pull request #296 from vaspahomov/feature/disconnect-in-reconcile
Add Disconnect call in Reconcile
2021-12-02 14:16:43 -08:00
Nic Cope 21928d24c8
Merge pull request #303 from fahedouch/add-nop-finalizer
add NewNopFinalizer()
2021-11-22 10:13:03 -08:00
fahed dorgaa 7b45316e5b add NewNopFinalizer
Signed-off-by: fahed dorgaa <fahed.dorgaa@gmail.com>
2021-11-08 12:49:03 +01:00
Daniel Mangum c72bcdd922
Merge pull request #300 from hasheddan/better-parse
Only attempt object scheme parsing if object is not registered in meta
2021-10-29 17:13:07 -04:00
hasheddan f3ea898989
Use Wrapf for annotating parser errors
Updates error annotation formatting to use errors.Wrapf.

Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
2021-10-29 17:00:55 -04:00
hasheddan cc6f044e79
Only attempt object scheme parsing if object is not registered in meta
Updates the package parsing logic to only attempt decoding with the
object scheme in the case that the error from decoding in the meta
scheme is due to the GVK not being registered. This does not change the
definition of a valid package, but does result in more informative
errors being returned when a package is invalid due to a malformed meta
type.

Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
2021-10-29 15:51:06 -04:00
vaspahomov a5ff67d5a0
remove named returns; disconnect error should not requeue reconcile
Signed-off-by: vaspahomov <vas2142553@gmail.com>
2021-10-28 15:25:12 +05:00
vaspahomov bf53464ca5
Add Disconnect call in Reconcile
Signed-off-by: vaspahomov <vas2142553@gmail.com>
2021-10-28 15:20:56 +05:00
Nic Cope 67edf4ae83
Merge pull request #294 from negz/re-re-re-reconcile
Support true global reconcile rate limiting
2021-10-25 12:33:55 -07:00
Nic Cope bf5d5512c2
Merge pull request #298 from negz/contextual
Plumb up reconciler contexts
2021-10-14 13:49:50 -07:00
Nic Cope ee4131e543 Plumb up reconciler contexts
I believe the Reconcile method started including a context in controller-runtime
v0.8.0, but it was never plumbed up. If I follow the contexts correctly the one
passed to Reconcile can be traced back to the one passed to mgr.Start, which is
typically a context that is cancelled on SIGTERM or SIGINT.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-10-14 00:36:16 +00:00
muvaffak onuş 579c1833b5
Merge pull request #297 from turkenh/pave-with-wildcards
Add wildcard expand method to fieldpath.Paved
2021-10-04 18:08:27 +03:00
Hasan Turken 47bff13a91
Proper printing for wildcards
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2021-10-04 15:46:39 +03:00
Hasan Turken 77b66f3d77
Add unit tests for paved.ExpandWildcards
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2021-10-04 15:11:37 +03:00
Hasan Turken aefd94be9f
Add expand wildcards to Paved
Signed-off-by: Hasan Turken <turkenh@gmail.com>
2021-10-03 23:07:28 +03:00
muvaffak onuş d566121073
Merge pull request #295 from muvaf/finalize-it-now
managed: make finalizer name string public
2021-09-30 12:53:26 +03:00
Muvaffak Onus d6c9f3e919
managed: make finalizer name string public so that it can be used in NewAPIFinalizer calls outside of package managed
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2021-09-30 00:27:45 +03:00
Nic Cope 70a386a588 Return, don't mutate, a rate limited *rest.Config
Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-25 03:07:12 +00:00
Nic Cope f7ed086985 Don't rate limit requests that are already delayed by rate limiting
Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-25 02:41:39 +00:00
Nic Cope 277dabb3df Support true global reconcile rate limiting
This PR tweaks how ratelimiters are applied to support _actual_ global reconcile
rate limiting - that is all reconcile triggers are rate limited, not just some.

See https://github.com/crossplane/crossplane/issues/2595 for details.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-24 21:29:00 +00:00
Nic Cope 658dfc7b41
Merge pull request #293 from negz/coopt
Add a `controller.Options` type
2021-09-21 20:54:08 -07:00
Nic Cope f2b0ca3026 Add DefaultOptions
I don't really expect these to be used in practice. They're mostly useful for
places like the XRD controllers where we need a default set of options to plumb
down to the XR and XRC controllers when none are passed to use (i.e. in tests).

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-21 03:47:25 +00:00
Nic Cope d89312be2f Make nil *feature.Flags somewhat usable
This will report that flags aren't enabled if *Flags is nil, rather than panicing.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-21 03:46:06 +00:00
Nic Cope efa7256648 Add a convenience function for deriving controller-runtime options
Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-21 03:12:43 +00:00
Nic Cope b7335472cd Add a controller.Options type
This type is intended to be passed as the argument to most Crossplane Setup
functions, for example:

```go
func Setup(mgr ctrl.Manager, o controller.Options) error
```

This allows us to add new options to be plumbed down to all or most controllers
without increasing the number of arguments provided to each Setup function. Sets
of controllers that require additional arguments (e.g. the pkg controllers from
crossplane/crossplane) can define their own Options struct that embeds this one.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-21 03:12:43 +00:00
Nic Cope 6ae31519f1 Switch ratelimiter package to more generic names
I'd like to reuse these existing ratelimiters for crossplane, where the names
'Provider' and 'Managed' don't make as much sense.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-21 03:12:43 +00:00
Nic Cope 4bd8016876 Add a feature flag package
https://github.com/crossplane/crossplane/tree/b7ce021e32/internal/feature
https://github.com/crossplane/crossplane/issues/2313.

This is a copy of the (almost) identical crossplane/crossplane package, which
will be removed in favor of this one. Moving to crossplane-runtime allows us to
use the same package in providers, e.g. to disable Alpha APIs per the above
issue.

The package is _almost_ identical because the Flag type has been changed from
int to string. This makes it easier to give flags string names, because the
stringer tool we previously used requires that types and instances be defined in
the same package.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-21 03:12:43 +00:00
Nic Cope 9f3f799fbd
Merge pull request #292 from negz/creation
Set `Creating` and `Deleting` conditions close to `Status().Update()` calls
2021-09-17 16:43:39 -07:00
Nic Cope f1ff9b11b7 Set Creating and Deleting conditions close to Status().Update() calls
https://github.com/crossplane/crossplane-runtime/issues/285

This approach causes us to repeat ourselves a bit, but prevents issues like the
above, where refactoring caused us to accidentally overwrite a pending status
update that we hadn't committed.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-17 23:35:29 +00:00
Nic Cope fe7e495016 Mark Target APIs as deprecated.
I don't believe these are used anywhere anymore.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-13 22:17:52 +00:00
Nic Cope 6a7a44ac50
Merge pull request #291 from negz/error
Add an `errors` package with a similar API to `github.com/pkg/errors`
2021-09-12 18:54:52 -07:00
Nic Cope 3aa81c43b1 Remove TODO about cmpopts.EquateErrors
I tried to address this TODO today, but found that I kind of prefer how our
implementation works. I've found from time to time while writing tests that
I was accidentally wrapping my errors with the wrong context (i.e. message),
which is not something the cmpopts variant tests for.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-09 07:50:57 +00:00
Nic Cope af4e148a11 Replace github.com/pkg/errors with our own pkg/errors.
Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-09 07:50:57 +00:00
Nic Cope 1a64750fcd Add an errors package with a similar API to github.com/pkg/errors
Go introduced a 'native' way to wrap errors back in v1.13. At that point we were
already using github.com/pkg/errors to 'wrap' errors with context, and we never
got around to migrating. In addition to pure inertia, I've personally avoided
making the switch because I prefer the github.com/pkg/errors API. Specifically I
like that errors.Wrap handles the "outer context: inner context" error format
that Go uses by convention, and that errors.Wrap will return nil when passed a
nil error.

Given that github.com/pkg/errors has long been in maintenance mode, and is (per
https://github.com/pkg/errors/issues/245) no longer used by its original author
now seems as good a time as any to migrate. This commit attempts to ease that
migration for the Crossplane project - and to retain the nice API - by adding a
package that acts as a small github.com/pkg/errors style shim layer around the
stdlib pkg/errors (and friends, like fmt.Errorf).

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-09 07:43:25 +00:00
Nic Cope 9779b31a42
Merge pull request #287 from negz/flows
Add commands Github workflow
2021-09-07 14:36:05 -07:00
Nic Cope d3a1443b70 Add commands Github workflow
This is primarily for the /backport command that we can use to backport merged PRs.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-07 21:26:30 +00:00
Nic Cope 4d28ff19e2
Merge pull request #286 from negz/flows
Add backport workflow
2021-09-07 14:24:00 -07:00
Nic Cope f4556df2c6 Add backport workflow
We recently started using release branches for crossplane-runtime, so this will
help backport patches.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-07 21:08:35 +00:00
Nic Cope 1d64e228e1
Merge pull request #283 from negz/creat
Account for two different kinds of consistency issues
2021-09-03 13:16:29 -07:00
Nic Cope 8e780ecd6d Don't rely on removal of the external-create-pending annotation
The retry logic we use to persist critical annotations makes it difficult to
delete an annotation without potentially also deleting annotations added by
another controller (e.g. the composition logic). This commit therefore changes
the way we detect whether we might have created an external resource but not
recorded the result. Previously we relied on the presence of the 'pending'
annotation to detect this state. Now we check whether the 'pending' annotation
is newer than any 'succeeded' or 'failed' annotation.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-03 04:41:00 +00:00
Nic Cope a3a59c95b6 Account for two different kinds of consistency issues
This commit is intended to address two issues that we diagnosed while
investigating https://github.com/crossplane/provider-aws/issues/802.

The first issue is that controller-runtime does not guarantee reads from cache
will return the freshest version of a resource. It's possible we could create an
external resource in one reconcile, then shortly after trigger another in which
it appears that the managed resource was never created because we didn't record
its external-name. This only affects the subset of managed resources with
non-deterministic external-names that are assigned during creation.

The second issue is that some external APIs are eventually consistent. A newly
created external resource may take some time before our ExternalClient's observe
call can confirm it exists. AWS EC2 is an example of one such API.

This commit attempts to address the first issue by making an Update to a managed
resource immediately before Create it called. This Update call will be rejected
by the API server if the managed resource we read from cache was not the latest
version.

It attempts to address the second issue by allowing managed resource controller
authors to configure an optional grace period that begins when an external
resource is successfully created. During this grace period we'll requeue and
keep waiting if Observe determines that the external resource doesn't exist,
rather than (re)creating it.

Signed-off-by: Nic Cope <negz@rk0n.org>
2021-09-01 06:04:31 +00:00
Nic Cope 589072e678
Merge pull request #284 from muvaf/upd-dependencies
Update dependencies
2021-08-31 17:29:57 -07:00
Muvaffak Onus 202adf8c80
build: update build submodule
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2021-08-31 11:50:16 +03:00
Muvaffak Onus 0467f337a0
go.mod: update go version to 1.16
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2021-08-31 10:42:44 +03:00
Muvaffak Onus 1aa48e39fa
go.mod: update all dependencies to latest versions
Signed-off-by: Muvaffak Onus <me@muvaf.com>
2021-08-31 10:41:34 +03:00
Nic Cope ba474e81c6
Merge pull request #273 from negz/revupyourengines
Add composition revision support to XRs and XRCs
2021-08-11 19:00:58 -07:00
Nic Cope 047d9387ef
Merge pull request #270 from ulucinar/aru/fix-2211
Support merging in addition to replacing objects in patches
2021-08-05 15:07:29 -07:00
Alper Rifat Ulucinar 0127cd0781
Improve comments on fieldpath.merge
Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2021-08-05 18:22:32 +03:00
Alper Rifat Ulucinar 4d6ec580be
Do not append duplicate slice elements when MergeOptions.AppendSlice is set
- Move resource.WithMergeOptions to core Crossplane and unexport
- Move fieldpath.object functions to core Crossplane and unexport
- Move fieldpath.MergeValue & related functions to its own file
- Add tests for fieldpath.MergeValue

Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2021-08-04 21:38:43 +03:00
Alper Rifat Ulucinar e7b4a22e42
Add Paved.MargeValue method
- Add "fieldpath/object" package that deals with runtime.Objects
- Move MergeOptions struct to package "apis/common/v1".

Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2021-08-02 14:19:03 +03:00
Alper Rifat Ulucinar fcbfd04067
Add tests for merge.go
- Add MergeReplace in fieldpath package for
  ease of writing tests.

Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2021-08-02 14:19:02 +03:00
Alper Rifat Ulucinar 6f106aac89
Support merging in addition to replacing objects in patches
Signed-off-by: Alper Rifat Ulucinar <ulucinar@users.noreply.github.com>
2021-08-02 14:18:53 +03:00
Nic Cope 0b469fcc77
Merge pull request #272 from alecrajeev/Add-Verbose-Logging-Observe
Added verbose logging option when resource is updated
2021-07-21 17:59:35 -07:00
Nic Cope cb68ff958f Add composition revision support to XRs and XRCs
Signed-off-by: Nic Cope <negz@rk0n.org>
2021-07-22 00:51:16 +00:00
Alec Rajeev 5193d240d4 Improve name and log message
Signed-off-by: Alec Rajeev <alecinthecloud@gmail.com>
2021-07-13 20:16:39 -04:00
Nic Cope 85b19c28ea
Merge pull request #267 from saschagrunert/controller-runtime
Update controller-runtime to v0.9.2
2021-07-13 12:40:31 -07:00
Sascha Grunert 18438ce2cf
Update controller-runtime to v0.9.2
This patch updates the controller-runtime dependency to the latest
release.

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
2021-07-12 09:24:23 +02:00
Alec Rajeev 4eb03bf865 Added verbose logging option when resource is updated
Signed-off-by: Alec Rajeev <alecinthecloud@gmail.com>
2021-07-11 21:27:21 -04:00
166 changed files with 22900 additions and 6058 deletions

View File

@ -1,35 +1,32 @@
<!--
Thank you for helping to improve Crossplane!
Please read through https://git.io/fj2m9 if this is your first time opening a
Crossplane pull request. Find us in https://slack.crossplane.io/messages/dev if
you need any help contributing.
Thank you for helping to improve Crossplane! Please read the contribution docs
(linked below) if this is your first Crossplane pull request.
-->
### Description of your changes
<!--
Briefly describe what this pull request does. Be sure to direct your reviewers'
attention to anything that needs special consideration.
We love pull requests that resolve an open Crossplane issue. If yours does, you
can uncomment the below line to indicate which issue your PR fixes, for example
"Fixes #500":
Briefly describe what this pull request does, and how it is covered by tests.
Be proactive - direct your reviewers' attention to anything that needs special
consideration.
We love pull requests that fix an open issue. If yours does, use the below line
to indicate which issue it fixes, for example "Fixes #500".
-->
Fixes #
I have:
Fixes #
I have: <!--You MUST either [x] check or [ ] ~strike through~ every item.-->
- [ ] Read and followed Crossplane's [contribution process].
- [ ] Run `make reviewable test` to ensure this PR is ready for review.
- [ ] Run `earthly +reviewable` to ensure this PR is ready for review.
- [ ] Added or updated unit tests.
- [ ] Linked a PR or a [docs tracking issue] to [document this change].
- [ ] Added `backport release-x.y` labels to auto-backport this PR.
### How has this code been tested
Need help with this checklist? See the [cheat sheet].
<!--
Before reviewers can be confident in the correctness of this pull request, it
needs to tested and shown to be correct. Briefly describe the testing that has
already been done or which is planned for this change.
-->
[contribution process]: https://git.io/fj2m9
[contribution process]: https://github.com/crossplane/crossplane/tree/main/contributing
[docs tracking issue]: https://github.com/crossplane/docs/issues/new
[document this change]: https://docs.crossplane.io/contribute/contribute
[cheat sheet]: https://github.com/crossplane/crossplane/tree/main/contributing#checklist-cheat-sheet

7
.github/renovate-entrypoint.sh vendored Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
curl -fsSLo /usr/local/bin/earthly https://github.com/earthly/earthly/releases/latest/download/earthly-linux-amd64
chmod +x /usr/local/bin/earthly
/usr/local/bin/earthly bootstrap
renovate

262
.github/renovate.json5 vendored Normal file
View File

@ -0,0 +1,262 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"helpers:pinGitHubActionDigests",
":semanticCommits"
],
// We only want renovate to rebase PRs when they have conflicts, default
// "auto" mode is not required.
"rebaseWhen": "conflicted",
// The maximum number of PRs to be created in parallel
"prConcurrentLimit": 5,
// The branches renovate should target
// PLEASE UPDATE THIS WHEN RELEASING.
"baseBranches": [
'main',
'release-1.18',
'release-1.19',
'release-1.20',
],
"ignorePaths": [
"design/**",
// We test upgrades, so leave it on an older version on purpose.
"test/e2e/manifests/pkg/provider/provider-initial.yaml",
],
"postUpdateOptions": [
"gomodTidy"
],
// All PRs should have a label
"labels": [
"automated"
],
"customManagers": [
{
"customType": "regex",
"description": "Bump Earthly version in GitHub workflows",
"fileMatch": [
"^\\.github\\/workflows\\/[^/]+\\.ya?ml$"
],
"matchStrings": [
"EARTHLY_VERSION: '(?<currentValue>.*?)'\\n"
],
"datasourceTemplate": "github-releases",
"depNameTemplate": "earthly/earthly",
"extractVersionTemplate": "^v(?<version>.*)$"
},
{
"customType": "regex",
"description": "Bump Go version in Earthfile",
"fileMatch": [
"^Earthfile$"
],
"matchStrings": [
"ARG --global GO_VERSION=(?<currentValue>.*?)\\n"
],
"datasourceTemplate": "golang-version",
"depNameTemplate": "golang"
},
{
"customType": "regex",
"description": "Bump golangci-lint version in the Earthfile",
"fileMatch": [
"^Earthfile$"
],
"matchStrings": [
"ARG GOLANGCI_LINT_VERSION=(?<currentValue>.*?)\\n"
],
"datasourceTemplate": "github-releases",
"depNameTemplate": "golangci/golangci-lint"
},
{
"customType": "regex",
"description": "Bump codeql version in the Earthfile",
"fileMatch": [
"^Earthfile$"
],
"matchStrings": [
"ARG CODEQL_VERSION=(?<currentValue>.*?)\\n"
],
"datasourceTemplate": "github-releases",
"depNameTemplate": "github/codeql-action",
"extractVersionTemplate": "^codeql-bundle-(?<version>.*)$"
},
],
// Renovate doesn't have native Earthfile support, but because Earthfile
// syntax is a superset of Dockerfile syntax this works to update FROM images.
// https://github.com/renovatebot/renovate/issues/15975
"dockerfile": {
"fileMatch": [
"(^|/)Earthfile$"
]
},
// PackageRules disabled below should be enabled in case of vulnerabilities
"vulnerabilityAlerts": {
"enabled": true
},
"osvVulnerabilityAlerts": true,
// Renovate evaluates all packageRules in order, so low priority rules should
// be at the beginning, high priority at the end
"packageRules": [
{
"description": "Generate code after upgrading go dependencies (main)",
"matchDatasources": [
"go"
],
// Currently we only have an Earthfile on main and some release branches, so we ignore the ones we know don't have it.
matchBaseBranches: [
'!/release-1\.16/',
],
postUpgradeTasks: {
// Post-upgrade tasks that are executed before a commit is made by Renovate.
"commands": [
"earthly --strict +go-generate",
],
fileFilters: [
"**/*"
],
executionMode: "update",
},
},
{
"description": "Generate code after upgrading go dependencies (release branch)",
"matchDatasources": [
"go"
],
// Currently we only have an Earthfile on main and some release branches, so we only run this on older release branches.
matchBaseBranches: [
'release-1.16',
],
postUpgradeTasks: {
// Post-upgrade tasks that are executed before a commit is made by Renovate.
"commands": [
"make go.generate",
],
fileFilters: [
"**/*"
],
executionMode: "update",
},
},
{
"description": "Lint code after upgrading golangci-lint (main)",
"matchDepNames": [
"golangci/golangci-lint"
],
// Currently we only have an Earthfile on main and some release branches, so we ignore the ones we know don't have it.
matchBaseBranches: [
'!/release-1\.16/',
],
postUpgradeTasks: {
// Post-upgrade tasks that are executed before a commit is made by Renovate.
"commands": [
"earthly --strict +go-lint",
],
fileFilters: [
"**/*"
],
executionMode: "update",
},
},
{
"description": "Lint code after upgrading golangci-lint (release branch)",
"matchDepNames": [
"golangci/golangci-lint"
],
// Currently we only have an Earthfile on main and some release branches, so we only run this on older release branches.
matchBaseBranches: [
'release-1.16',
],
postUpgradeTasks: {
// Post-upgrade tasks that are executed before a commit is made by Renovate.
"commands": [
"make go.lint",
],
fileFilters: [
"**/*"
],
executionMode: "update",
},
},
{
"description": "Ignore non-security related updates to release branches",
matchBaseBranches: [
"/^release-.*/"
],
enabled: false,
},
{
"description": "Still update Docker images on release branches though",
"matchDatasources": [
"docker"
],
matchBaseBranches: [
"/^release-.*/"
],
enabled: true,
},
{
"description": "Only get Docker image updates every 2 weeks to reduce noise",
"matchDatasources": [
"docker"
],
"schedule": [
"every 2 week on monday"
],
enabled: true,
},
{
"description": "Ignore k8s.io/client-go older versions, they switched to semantic version and old tags are still available in the repo",
"matchDatasources": [
"go"
],
"matchDepNames": [
"k8s.io/client-go"
],
"allowedVersions": "<1.0",
},
{
"description": "Ignore k8s dependencies, should be updated on crossplane-runtime",
"matchDatasources": [
"go"
],
"matchPackagePrefixes": [
"k8s.io",
"sigs.k8s.io"
],
"enabled": false,
},
{
"description": "Only get dependency digest updates every month to reduce noise, except crossplane-runtime",
"excludePackageNames": [
"github.com/crossplane/crossplane-runtime"
],
"matchDatasources": [
"go"
],
"matchUpdateTypes": [
"digest",
],
"extends": [
"schedule:monthly"
],
},
{
"description": "Ignore oss-fuzz, it's not using tags, we'll stick to master",
"matchDepTypes": [
"action"
],
"matchDepNames": [
"google/oss-fuzz"
],
"enabled": false
},
{
"description": "Group all go version updates",
"matchDatasources": [
"golang-version"
],
"groupName": "golang version",
}
],
}

38
.github/stale.yml vendored
View File

@ -1,38 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- security
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Label to use when marking as stale
staleLabel: wontfix
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue has been automatically closed due to inactivity. Please re-open
if this still requires investigation.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
only: issues

33
.github/workflows/backport.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: Backport
on:
# NOTE(negz): This is a risky target, but we run this action only when and if
# a PR is closed, then filter down to specifically merged PRs. We also don't
# invoke any scripts, etc from within the repo. I believe the fact that we'll
# be able to review PRs before this runs makes this fairly safe.
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
pull_request_target:
types: [closed]
# See also commands.yml for the /backport triggered variant of this workflow.
jobs:
# NOTE(negz): I tested many backport GitHub actions before landing on this
# one. Many do not support merge commits, or do not support pull requests with
# more than one commit. This one does. It also handily links backport PRs with
# new PRs, and provides commentary and instructions when it can't backport.
# The main gotchas with this action are that it _only_ supports merge commits,
# and that PRs _must_ be labelled before they're merged to trigger a backport.
open-pr:
runs-on: ubuntu-22.04
if: github.event.pull_request.merged
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Open Backport PR
uses: zeebe-io/backport-action@ef20d86abccbac3ee3a73cb2efbdc06344c390e5 # v2.5.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_workspace: ${{ github.workspace }}

View File

@ -3,315 +3,243 @@ name: CI
on:
push:
branches:
- master
- main
- release-*
pull_request: {}
workflow_dispatch: {}
env:
# Common versions
GO_VERSION: '1.14'
GOLANGCI_VERSION: 'v1.31'
DOCKER_BUILDX_VERSION: 'v0.4.2'
EARTHLY_VERSION: '0.8.15'
# Force Earthly to use color output
FORCE_COLOR: "1"
# 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
# credentials have been provided before trying to run steps that need them.
DOCKER_USR: ${{ secrets.DOCKER_USR }}
AWS_USR: ${{ secrets.AWS_USR }}
jobs:
detect-noop:
runs-on: ubuntu-18.04
outputs:
noop: ${{ steps.noop.outputs.should_skip }}
steps:
- name: Detect No-op Changes
id: noop
uses: fkirc/skip-duplicate-actions@v2.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
paths_ignore: '["**.md", "**.png", "**.jpg"]'
do_not_skip: '["workflow_dispatch", "schedule", "push"]'
lint:
runs-on: ubuntu-18.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
- name: Cache the Go Build Cache
uses: actions/cache@v2
with:
path: ${{ steps.go.outputs.cache }}
key: ${{ runner.os }}-build-lint-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-build-lint-
- name: Cache Go Dependencies
uses: actions/cache@v2
with:
path: .work/pkg
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-pkg-
- name: Vendor Dependencies
run: make vendor vendor.check
# This action uses its own setup-go, which always seems to use the latest
# stable version of Go. We could run 'make lint' to ensure our desired Go
# version, but we prefer this action because it leaves 'annotations' (i.e.
# it comments on PRs to point out linter violations).
- name: Lint
uses: golangci/golangci-lint-action@v2
with:
version: ${{ env.GOLANGCI_VERSION }}
check-diff:
runs-on: ubuntu-18.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Earthly
uses: earthly/actions-setup@v1
with:
submodules: true
github-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.EARTHLY_VERSION }}
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
- name: Cache the Go Build Cache
uses: actions/cache@v2
with:
path: ${{ steps.go.outputs.cache }}
key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-build-check-diff-
- name: Cache Go Dependencies
uses: actions/cache@v2
with:
path: .work/pkg
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-pkg-
- name: Vendor Dependencies
run: make vendor vendor.check
- name: Check Diff
run: make check-diff
unit-tests:
runs-on: ubuntu-18.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Fetch History
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
- name: Cache the Go Build Cache
uses: actions/cache@v2
with:
path: ${{ steps.go.outputs.cache }}
key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-build-unit-tests-
- name: Cache Go Dependencies
uses: actions/cache@v2
with:
path: .work/pkg
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-pkg-
- name: Vendor Dependencies
run: make vendor vendor.check
- name: Run Unit Tests
run: make -j2 test
- name: Publish Unit Test Coverage
uses: codecov/codecov-action@v1
with:
flags: unittests
file: _output/tests/linux_amd64/coverage.txt
e2e-tests:
runs-on: ubuntu-18.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'
steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
with:
version: ${{ env.DOCKER_BUILDX_VERSION }}
install: true
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Fetch History
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
- name: Cache the Go Build Cache
uses: actions/cache@v2
with:
path: ${{ steps.go.outputs.cache }}
key: ${{ runner.os }}-build-e2e-tests-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-build-e2e-tests-
- name: Cache Go Dependencies
uses: actions/cache@v2
with:
path: .work/pkg
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-pkg-
- name: Vendor Dependencies
run: make vendor vendor.check
- name: Build Helm Chart
run: make -j2 build
env:
# We're using docker buildx, which doesn't actually load the images it
# builds by default. Specifying --load does so.
BUILD_ARGS: "--load"
- name: Run E2E Tests
run: make e2e USE_HELM3=true
publish-artifacts:
runs-on: ubuntu-18.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'
steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
with:
version: ${{ env.DOCKER_BUILDX_VERSION }}
install: true
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Fetch History
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- name: Find the Go Build Cache
id: go
run: echo "::set-output name=cache::$(go env GOCACHE)"
- name: Cache the Go Build Cache
uses: actions/cache@v2
with:
path: ${{ steps.go.outputs.cache }}
key: ${{ runner.os }}-build-publish-artifacts-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-build-publish-artifacts-
- name: Cache Go Dependencies
uses: actions/cache@v2
with:
path: .work/pkg
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-pkg-
- name: Vendor Dependencies
run: make vendor vendor.check
- name: Build Artifacts
run: make -j2 build.all
env:
# We're using docker buildx, which doesn't actually load the images it
# builds by default. Specifying --load does so.
BUILD_ARGS: "--load"
- name: Publish Artifacts to GitHub
uses: actions/upload-artifact@v2
with:
name: output
path: _output/**
- name: Login to Docker
uses: docker/login-action@v1
- name: Login to DockerHub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
if: env.DOCKER_USR != ''
with:
username: ${{ secrets.DOCKER_USR }}
password: ${{ secrets.DOCKER_PSW }}
- name: Publish Artifacts to S3 and Docker Hub
run: make -j2 publish BRANCH_NAME=${GITHUB_REF##*/}
if: env.AWS_USR != '' && env.DOCKER_USR != ''
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }}
GIT_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Promote Artifacts in S3 and Docker Hub
if: github.ref == 'refs/heads/master' && env.AWS_USR != '' && env.DOCKER_USR != ''
run: make -j2 promote
env:
BRANCH_NAME: master
CHANNEL: master
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }}
- name: Login to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Earthly to Push Cache to GitHub Container Registry
if: github.ref == 'refs/heads/main'
run: |
echo "EARTHLY_PUSH=true" >> $GITHUB_ENV
echo "EARTHLY_MAX_REMOTE_CACHE=true" >> $GITHUB_ENV
- name: Generate Files
run: earthly --strict --remote-cache ghcr.io/crossplane/crossplane-runtime-earthly-cache:${{ github.job }} +generate
- name: Count Changed Files
id: changed_files
run: echo "count=$(git status --porcelain | wc -l)" >> $GITHUB_OUTPUT
- name: Fail if Files Changed
if: steps.changed_files.outputs.count != 0
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: core.setFailed('Found changed files after running earthly +generate.')
lint:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Earthly
uses: earthly/actions-setup@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.EARTHLY_VERSION }}
- name: Login to DockerHub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
if: env.DOCKER_USR != ''
with:
username: ${{ secrets.DOCKER_USR }}
password: ${{ secrets.DOCKER_PSW }}
- name: Login to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Earthly to Push Cache to GitHub Container Registry
if: github.ref == 'refs/heads/main'
run: |
echo "EARTHLY_PUSH=true" >> $GITHUB_ENV
echo "EARTHLY_MAX_REMOTE_CACHE=true" >> $GITHUB_ENV
- name: Lint
run: earthly --strict --remote-cache ghcr.io/crossplane/crossplane-runtime-earthly-cache:${{ github.job }} +lint
codeql:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Earthly
uses: earthly/actions-setup@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.EARTHLY_VERSION }}
- name: Login to DockerHub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
if: env.DOCKER_USR != ''
with:
username: ${{ secrets.DOCKER_USR }}
password: ${{ secrets.DOCKER_PSW }}
- name: Login to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Earthly to Push Cache to GitHub Container Registry
if: github.ref == 'refs/heads/main'
run: |
echo "EARTHLY_PUSH=true" >> $GITHUB_ENV
echo "EARTHLY_MAX_REMOTE_CACHE=true" >> $GITHUB_ENV
- name: Run CodeQL
run: earthly --strict --remote-cache ghcr.io/crossplane/crossplane-runtime-earthly-cache:${{ github.job }} +ci-codeql
- name: Upload CodeQL Results to GitHub
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3
with:
sarif_file: '_output/codeql/go.sarif'
trivy-scan-fs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Run Trivy vulnerability scanner in fs mode
uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0
with:
scan-type: 'fs'
ignore-unfixed: true
skip-dirs: design
scan-ref: '.'
severity: 'CRITICAL,HIGH'
format: sarif
output: 'trivy-results.sarif'
- name: Upload Trivy Results to GitHub
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3
with:
sarif_file: 'trivy-results.sarif'
unit-tests:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Earthly
uses: earthly/actions-setup@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version: ${{ env.EARTHLY_VERSION }}
- name: Login to DockerHub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
if: env.DOCKER_USR != ''
with:
username: ${{ secrets.DOCKER_USR }}
password: ${{ secrets.DOCKER_PSW }}
- name: Login to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Earthly to Push Cache to GitHub Container Registry
if: github.ref == 'refs/heads/main'
run: |
echo "EARTHLY_PUSH=true" >> $GITHUB_ENV
echo "EARTHLY_MAX_REMOTE_CACHE=true" >> $GITHUB_ENV
- name: Run Unit Tests
run: earthly --strict --remote-cache ghcr.io/crossplane/crossplane-runtime-earthly-cache:${{ github.job }} +test
- name: Publish Unit Test Coverage
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
flags: unittests
file: _output/tests/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
protobuf-schemas:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Buf
uses: bufbuild/buf-setup-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Lint Protocol Buffers
uses: bufbuild/buf-lint-action@v1
with:
input: apis
# buf-breaking-action doesn't support branches
# https://github.com/bufbuild/buf-push-action/issues/34
- name: Detect Breaking Changes in Protocol Buffers
uses: bufbuild/buf-breaking-action@a074e988ee34efcd4927079e79c611f428354c01 # v1
# We want to run this for the main branch, and PRs against main.
if: ${{ github.ref == 'refs/heads/main' || github.base_ref == 'main' }}
with:
input: apis
against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=main,subdir=apis"
- name: Push Protocol Buffers to Buf Schema Registry
if: ${{ github.repository == 'crossplane/crossplane-runtime' && github.ref == 'refs/heads/main' }}
uses: bufbuild/buf-push-action@v1
with:
input: apis
buf_token: ${{ secrets.BUF_TOKEN }}

111
.github/workflows/commands.yml vendored Normal file
View File

@ -0,0 +1,111 @@
name: Comment Commands
on: issue_comment
jobs:
points:
runs-on: ubuntu-22.04
if: startsWith(github.event.comment.body, '/points')
steps:
- name: Extract Command
id: command
uses: xt0rted/slash-command-action@bf51f8f5f4ea3d58abc7eca58f77104182b23e88 # v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
command: points
reaction: "true"
reaction-type: "eyes"
allow-edits: "false"
permission-level: write
- name: Handle Command
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
env:
POINTS: ${{ steps.command.outputs.command-arguments }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const points = process.env.POINTS
if (isNaN(parseInt(points))) {
console.log("Malformed command - expected '/points <int>'")
github.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: "confused"
})
return
}
const label = "points/" + points
// Delete our needs-points-label label.
try {
await github.issues.deleteLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: ['needs-points-label']
})
console.log("Deleted 'needs-points-label' label.")
}
catch(e) {
console.log("Label 'needs-points-label' probably didn't exist.")
}
// Add our points label.
github.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [label]
})
console.log("Added '" + label + "' label.")
# NOTE(negz): See also backport.yml, which is the variant that triggers on PR
# merge rather than on comment.
backport:
runs-on: ubuntu-22.04
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/backport')
steps:
- name: Extract Command
id: command
uses: xt0rted/slash-command-action@bf51f8f5f4ea3d58abc7eca58f77104182b23e88 # v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
command: backport
reaction: "true"
reaction-type: "eyes"
allow-edits: "false"
permission-level: write
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Open Backport PR
uses: zeebe-io/backport-action@ef20d86abccbac3ee3a73cb2efbdc06344c390e5 # v2.5.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_workspace: ${{ github.workspace }}
fresh:
runs-on: ubuntu-22.04
if: startsWith(github.event.comment.body, '/fresh')
steps:
- name: Extract Command
id: command
uses: xt0rted/slash-command-action@bf51f8f5f4ea3d58abc7eca58f77104182b23e88 # v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
command: fresh
reaction: "true"
reaction-type: "eyes"
allow-edits: "false"
permission-level: read
- name: Handle Command
uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: stale

View File

@ -1,49 +0,0 @@
name: Promote
on:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g. v0.1.0)'
required: true
channel:
description: 'Release channel'
required: true
default: 'alpha'
env:
# 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
# credentials have been provided before trying to run steps that need them.
DOCKER_USR: ${{ secrets.DOCKER_USR }}
AWS_USR: ${{ secrets.AWS_USR }}
jobs:
promote-artifacts:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: true
- name: Fetch History
run: git fetch --prune --unshallow
- name: Login to Docker
uses: docker/login-action@v1
if: env.DOCKER_USR != ''
with:
username: ${{ secrets.DOCKER_USR }}
password: ${{ secrets.DOCKER_PSW }}
- name: Promote Artifacts in S3 and Docker Hub
if: env.AWS_USR != '' && env.DOCKER_USR != ''
run: make -j2 promote BRANCH_NAME=${GITHUB_REF##*/}
env:
VERSION: ${{ github.event.inputs.version }}
CHANNEL: ${{ github.event.inputs.channel }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_USR }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_PSW }}

54
.github/workflows/renovate.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: Renovate
on:
# Allows manual/automated trigger for debugging purposes
workflow_dispatch:
inputs:
logLevel:
description: "Renovate's log level"
required: true
default: "info"
type: string
schedule:
- cron: '0 8 * * *'
env:
# Common versions
EARTHLY_VERSION: '0.8.15'
LOG_LEVEL: "info"
jobs:
renovate:
runs-on: ubuntu-latest
if: |
!github.event.repository.fork &&
!github.event.pull_request.head.repo.fork
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Don't waste time starting Renovate if JSON is invalid
- name: Validate Renovate JSON
run: npx --yes --package renovate -- renovate-config-validator
- name: Get token
id: get-github-app-token
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
with:
app-id: ${{ secrets.RENOVATE_GITHUB_APP_ID }}
private-key: ${{ secrets.RENOVATE_GITHUB_APP_PRIVATE_KEY }}
- name: Self-hosted Renovate
uses: renovatebot/github-action@0984fb80fc633b17e57f3e8b6c007fe0dc3e0d62 # v40.3.6
env:
RENOVATE_REPOSITORIES: ${{ github.repository }}
# Use GitHub API to create commits
RENOVATE_PLATFORM_COMMIT: "true"
LOG_LEVEL: ${{ github.event.inputs.logLevel || env.LOG_LEVEL }}
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^earthly .+"]'
with:
configurationFile: .github/renovate.json5
token: '${{ steps.get-github-app-token.outputs.token }}'
mount-docker-socket: true
docker-user: root
docker-cmd-file: .github/renovate-entrypoint.sh

47
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,47 @@
name: Stale Issues and PRs
on:
schedule:
# Process new stale issues once a day. Folks can /fresh for a fast un-stale
# per the commands workflow. Run at 1:15 mostly as a somewhat unique time to
# help correlate any issues with this workflow.
- cron: '15 1 * * *'
workflow_dispatch: {}
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-22.04
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
with:
# This action uses ~2 operations per stale issue per run to determine
# whether it's still stale. It also uses 2-3 operations to mark an issue
# stale or not. During steady state (no issues to mark stale, check, or
# close) we seem to use less than 10 operations with ~150 issues and PRs
# open.
#
# Our hourly rate-limit budget for all workflows that use GITHUB_TOKEN
# is 1,000 requests per the below docs.
# https://docs.github.com/en/rest/overview/resources-in-the-rest-api#requests-from-github-actions
operations-per-run: 100
days-before-stale: 90
days-before-close: 14
stale-issue-label: stale
exempt-issue-labels: exempt-from-stale
stale-issue-message: >
Crossplane does not currently have enough maintainers to address every
issue and pull request. This issue has been automatically marked as
`stale` because it has had no activity in the last 90 days. It will be
closed in 14 days if no further activity occurs. Leaving a comment
**starting with** `/fresh` will mark this issue as not stale.
stale-pr-label: stale
exempt-pr-labels: exempt-from-stale
stale-pr-message:
Crossplane does not currently have enough maintainers to address every
issue and pull request. This pull request has been automatically
marked as `stale` because it has had no activity in the last 90 days.
It will be closed in 14 days if no further activity occurs.
Adding a comment **starting with** `/fresh` will mark this PR as not stale.

View File

@ -12,15 +12,15 @@ on:
jobs:
create-tag:
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Create Tag
uses: negz/create-tag@v1
uses: negz/create-tag@39bae1e0932567a58c20dea5a1a0d18358503320 # v1
with:
version: ${{ github.event.inputs.version }}
message: ${{ github.event.inputs.message }}
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "build"]
path = build
url = https://github.com/upbound/build

View File

@ -1,202 +1,265 @@
run:
timeout: 10m
skip-files:
- "zz_generated\\..+\\.go$"
version: "2"
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: colored-line-number
linters-settings:
errcheck:
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*
govet:
# report about shadowed variables
check-shadowing: false
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
goimports:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
local-prefixes: github.com/crossplane/crossplane
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 10
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
dupl:
# tokens count to trigger issue, 150 by default
threshold: 100
goconst:
# minimal length of string constant, 3 by default
min-len: 3
# minimal occurrences count to trigger, 3 by default
min-occurrences: 5
lll:
# tab width in spaces. Default to 1.
tab-width: 1
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
nakedret:
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
max-func-lines: 30
prealloc:
# XXX: we don't recommend using this linter before doing performance profiling.
# For most programs usage of prealloc will be a premature optimization.
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
# True by default.
simple: true
range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default
gocritic:
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks.
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
enabled-tags:
- performance
settings: # settings passed to gocritic
captLocal: # must be valid enabled check name
paramsOnly: true
rangeValCopy:
sizeThreshold: 32
formats:
text:
path: stderr
linters:
enable:
- megacheck
- govet
default: all
disable:
# These are linters we'd like to enable, but that will be labor intensive to
# make existing code compliant.
- wrapcheck
- varnamelen
- testpackage
- paralleltest
- nilnil
- funcorder
# Below are linters that lint for things we don't value. Each entry below
# this line must have a comment explaining the rationale.
# These linters add whitespace in an attempt to make code more readable.
# This isn't a widely accepted Go best practice, and would be laborious to
# apply to existing code.
- wsl
- nlreturn
# Warns about uses of fmt.Sprintf that are less performant than alternatives
# such as string concatenation. We value readability more than performance
# unless performance is measured to be an issue.
- perfsprint
# This linter:
#
# 1. Requires errors.Is/errors.As to test equality.
# 2. Requires all errors be wrapped with fmt.Errorf specifically.
# 3. Disallows errors.New inline - requires package level errors.
#
# 1 is covered by other linters. 2 is covered by wrapcheck, which can also
# handle our use of crossplane-runtime's errors package. 3 is more strict
# than we need. Not every error needs to be tested for equality.
- err113
# These linters duplicate gocognit, but calculate complexity differently.
- gocyclo
- gocritic
- interfacer
- goconst
- goimports
- gofmt # We enable this as well as goimports for its simplify mode.
- prealloc
- golint
- unconvert
- misspell
- nakedret
- cyclop
- nestif
- funlen
- maintidx
presets:
- bugs
- unused
fast: false
# Enforces max line length. It's not idiomatic to enforce a strict limit on
# line length in Go. We'd prefer to lint for things that often cause long
# lines, like functions with too many parameters or long parameter names
# that duplicate their types.
- lll
# Warns about struct instantiations that don't specify every field. Could be
# useful in theory to catch fields that are accidentally omitted. Seems like
# it would have many more false positives than useful catches, though.
- exhaustruct
# Warns about TODO comments. The rationale being they should be issues
# instead. We're okay with using TODO to track minor cleanups for next time
# we touch a particular file.
- godox
# Warns about duplicated code blocks within the same file. Could be useful
# to prompt folks to think about whether code should be broken out into a
# function, but generally we're less worried about DRY and fine with a
# little copying. We don't want to give folks the impression that we require
# every duplicated code block to be factored out into a function.
- dupl
# Warns about returning interfaces rather than concrete types. We do think
# it's best to avoid returning interfaces where possible. However, at the
# time of writing enabling this linter would only catch the (many) cases
# where we must return an interface.
- ireturn
# Warns about returning named variables. We do think it's best to avoid
# returning named variables where possible. However, at the time of writing
# enabling this linter would only catch the (many) cases where returning
# named variables is useful to document what the variables are. For example
# we believe it makes sense to return (ready bool) rather than just (bool)
# to communicate what the bool means.
- nonamedreturns
# Warns about using magic numbers. We do think it's best to avoid magic
# numbers, but we should not be strict about it.
- mnd
# Warns about if err := Foo(); err != nil style error checks. Seems to go
# against idiomatic Go programming, which encourages this approach - e.g.
# to scope errors.
- noinlineerr
settings:
depguard:
rules:
no_third_party_test_libraries:
list-mode: lax
files:
- $test
deny:
- pkg: github.com/stretchr/testify
desc: See https://go.dev/wiki/TestComments#assert-libraries
- pkg: github.com/onsi/ginkgo
desc: See https://go.dev/wiki/TestComments#assert-libraries
- pkg: github.com/onsi/gomega
desc: See https://go.dev/wiki/TestComments#assert-libraries
dupl:
threshold: 100
errcheck:
check-type-assertions: false
check-blank: false
goconst:
min-len: 3
min-occurrences: 5
gocritic:
enabled-tags:
- performance
settings:
captLocal:
paramsOnly: true
rangeValCopy:
sizeThreshold: 32
govet:
disable:
- shadow
interfacebloat:
max: 5
lll:
tab-width: 1
nakedret:
max-func-lines: 30
nolintlint:
require-explanation: true
require-specific: true
prealloc:
simple: true
range-loops: true
for-loops: false
tagliatelle:
case:
rules:
json: goCamel
unparam:
check-exported: false
unused:
exported-fields-are-used: true
exclusions:
generated: lax
rules:
- linters:
- containedctx
- errcheck
- forcetypeassert
- gochecknoglobals
- gochecknoinits
- gocognit
- gosec
- scopelint
- unparam
- embeddedstructfieldcheck
path: _test(ing)?\.go
- linters:
- gocritic
path: _test\.go
text: (unnamedResult|exitAfterDefer)
# It's idiomatic to register Kubernetes types with a package scoped
# SchemeBuilder using an init function.
- linters:
- gochecknoglobals
- gochecknoinits
path: apis/
# These are performance optimisations rather than style issues per se.
# They warn when function arguments or range values copy a lot of memory
# rather than using a pointer.
- linters:
- gocritic
text: '(hugeParam|rangeValCopy):'
# This "TestMain should call os.Exit to set exit code" warning is not clever
# enough to notice that we call a helper method that calls os.Exit.
- linters:
- staticcheck
text: 'SA3000:'
# This is a "potential hardcoded credentials" warning. It's triggered by
# any variable with 'secret' in the same, and thus hits a lot of false
# positives in Kubernetes land where a Secret is an object type.
- linters:
- gosec
text: 'G101:'
# This is an 'errors unhandled' warning that duplicates errcheck.
- linters:
- gosec
text: 'G104:'
# This is about implicit memory aliasing in a range loop.
# This is a false positive with Go v1.22 and above.
- linters:
- gosec
text: 'G601:'
# Some k8s dependencies do not have JSON tags on all fields in structs.
- linters:
- musttag
path: k8s.io/
# Various fields related to native patch and transform Composition are
# deprecated, but we can't drop support from Crossplane 1.x. We ignore the
# warnings globally instead of suppressing them with comments everywhere.
- linters:
- staticcheck
text: 'SA1019: .+ is deprecated: Use Composition Functions instead.'
# Some shared structs in apis/common/v1 are moved to
# apis/common. To preserve a backward-compatible directory structure
# package had to be named common, which we suppress.
- linters:
- revive
text: "var-naming: avoid meaningless package names"
path: apis/common
paths:
- zz_generated\..+\.go$
- .+\.pb.go$
- third_party$
- builtin$
- examples$
issues:
# Excluding configuration per-path and per-linter
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test(ing)?\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- scopelint
- unparam
# Ease some gocritic warnings on test files.
- path: _test\.go
text: "(unnamedResult|exitAfterDefer)"
linters:
- gocritic
# These are performance optimisations rather than style issues per se.
# They warn when function arguments or range values copy a lot of memory
# rather than using a pointer.
- text: "(hugeParam|rangeValCopy):"
linters:
- gocritic
# This "TestMain should call os.Exit to set exit code" warning is not clever
# enough to notice that we call a helper method that calls os.Exit.
- text: "SA3000:"
linters:
- staticcheck
- text: "k8s.io/api/core/v1"
linters:
- goimports
# This is a "potential hardcoded credentials" warning. It's triggered by
# any variable with 'secret' in the same, and thus hits a lot of false
# positives in Kubernetes land where a Secret is an object type.
- text: "G101:"
linters:
- gosec
- gas
# This is an 'errors unhandled' warning that duplicates errcheck.
- text: "G104:"
linters:
- gosec
- gas
# The Azure AddToUserAgent method appends to the existing user agent string.
# It returns an error if you pass it an empty string lettinga you know the
# user agent did not change, making it more of a warning.
- text: \.AddToUserAgent
linters:
- errcheck
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
# Default value for this option is true.
exclude-use-default: false
# Show only new issues: if there are unstaged changes or untracked files,
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
# It's a super-useful option for integration of golangci-lint into existing
# large codebase. It's not practical to fix all existing issues at the moment
# of integration: much better don't allow issues in new code.
# Default is false.
max-issues-per-linter: 0
max-same-issues: 0
new: false
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
settings:
gci:
sections:
- standard
- default
- prefix(github.com/crossplane/crossplane-runtime)
- blank
- dot
custom-order: true
gofmt:
simplify: true
exclusions:
generated: lax
paths:
- zz_generated\..+\.go$
- .+\.pb.go$
- third_party$
- builtin$
- examples$

30
CODEOWNERS Normal file
View File

@ -0,0 +1,30 @@
# This file controls automatic PR reviewer assignment. See the following docs:
#
# * https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# * https://docs.github.com/en/organizations/organizing-members-into-teams/managing-code-review-settings-for-your-team
#
# The goal of this file is for most PRs to automatically and fairly have one
# maintainer and two reviewers set as PR reviewers. All maintainers have
# permission to approve and merge PRs, but reviewers do not. Most PRs should be
# reviewed by members of the reviewers group before being passed to a maintainer
# for final review.
#
# This in part depends on how the groups in this file are configured.
#
# @crossplane/steering-committee - Assigns 3 members. Admin perms to this repo.
# @crossplane/crossplane-maintainers - Assigns 1 member. Maintain perms to this repo.
# @crossplane/crossplane-reviewers - Assigns 2 members. Write perms to this repo.
#
# Where possible, prefer explicitly specifying a maintainer who is a subject
# matter expert for a particular part of the codebase rather than using the
# @crossplane/crossplane-maintainers group.
#
# See also OWNERS.md for governance details
# Fallback owners
* @crossplane/crossplane-maintainers
# Governance owners - steering committee
/README.md @crossplane/steering-committee
/OWNERS.md @crossplane/steering-committee
/LICENSE @crossplane/steering-committee

153
Earthfile Normal file
View File

@ -0,0 +1,153 @@
# See https://docs.earthly.dev/docs/earthfile/features
VERSION --try --raw-output 0.8
PROJECT crossplane/crossplane-runtime
ARG --global GO_VERSION=1.24.4
# reviewable checks that a branch is ready for review. Run it before opening a
# pull request. It will catch a lot of the things our CI workflow will catch.
reviewable:
WAIT
BUILD +generate
END
BUILD +lint
BUILD +test
# test runs unit tests.
test:
BUILD +go-test
# lint runs linters.
lint:
BUILD +go-lint
# build builds Crossplane for your native OS and architecture.
build:
BUILD +go-build
# multiplatform-build builds Crossplane for all supported OS and architectures.
multiplatform-build:
BUILD +go-multiplatform-build
# generate runs code generation. To keep builds fast, it doesn't run as part of
# the build target. It's important to run it explicitly when code needs to be
# generated, for example when you update an API type.
generate:
BUILD +go-modules-tidy
BUILD +go-generate
# go-modules downloads Crossplane's go modules. It's the base target of most Go
# related target (go-build, etc).
go-modules:
ARG NATIVEPLATFORM
FROM --platform=${NATIVEPLATFORM} golang:${GO_VERSION}
WORKDIR /crossplane
CACHE --id go-build --sharing shared /root/.cache/go-build
COPY go.mod go.sum ./
RUN go mod download
SAVE ARTIFACT go.mod AS LOCAL go.mod
SAVE ARTIFACT go.sum AS LOCAL go.sum
# go-modules-tidy tidies and verifies go.mod and go.sum.
go-modules-tidy:
FROM +go-modules
CACHE --id go-build --sharing shared /root/.cache/go-build
COPY --dir apis/ pkg/ .
RUN go mod tidy
RUN go mod verify
SAVE ARTIFACT go.mod AS LOCAL go.mod
SAVE ARTIFACT go.sum AS LOCAL go.sum
# go-generate runs Go code generation.
go-generate:
FROM +go-modules
CACHE --id go-build --sharing shared /root/.cache/go-build
COPY --dir apis/ hack/ .
RUN go generate -tags 'generate' ./apis/...
SAVE ARTIFACT apis/ AS LOCAL apis
# go-build builds Crossplane binaries for your native OS and architecture.
go-build:
ARG TARGETARCH
ARG TARGETOS
ARG GOARCH=${TARGETARCH}
ARG GOOS=${TARGETOS}
ARG CGO_ENABLED=0
FROM +go-modules
CACHE --id go-build --sharing shared /root/.cache/go-build
COPY --dir apis/ pkg/ .
RUN go build ./...
# go-multiplatform-build builds Crossplane binaries for all supported OS
# and architectures.
go-multiplatform-build:
BUILD \
--platform=linux/amd64 \
--platform=linux/arm64 \
--platform=linux/arm \
--platform=linux/ppc64le \
--platform=darwin/arm64 \
--platform=darwin/amd64 \
--platform=windows/amd64 \
+go-build
# go-test runs Go unit tests.
go-test:
FROM +go-modules
CACHE --id go-build --sharing shared /root/.cache/go-build
COPY --dir apis/ pkg/ .
RUN go test -covermode=count -coverprofile=coverage.txt ./...
SAVE ARTIFACT coverage.txt AS LOCAL _output/tests/coverage.txt
# go-lint lints Go code.
go-lint:
ARG GOLANGCI_LINT_VERSION=v2.2.1
FROM +go-modules
# This cache is private because golangci-lint doesn't support concurrent runs.
CACHE --id go-lint --sharing private /root/.cache/golangci-lint
CACHE --id go-build --sharing shared /root/.cache/go-build
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}
COPY .golangci.yml .
COPY --dir apis/ pkg/ .
RUN golangci-lint run --fix
SAVE ARTIFACT apis AS LOCAL apis
SAVE ARTIFACT pkg AS LOCAL pkg
# Targets below this point are intended only for use in GitHub Actions CI. They
# may not work outside of that environment. For example they may depend on
# secrets that are only availble in the CI environment. Targets below this point
# must be prefixed with ci-.
# TODO(negz): Is there a better way to determine the Crossplane version?
# This versioning approach maintains compatibility with the build submodule. See
# https://github.com/crossplane/build/blob/231258/makelib/common.mk#L205. This
# approach is problematic in Earthly because computing it inside a containerized
# target requires copying the entire git repository into the container. Doing so
# would invalidate all dependent target caches any time any file in git changed.
# ci-codeql-setup sets up CodeQL for the ci-codeql target.
ci-codeql-setup:
ARG CODEQL_VERSION=v2.20.5
FROM curlimages/curl:8.8.0
RUN curl -fsSL https://github.com/github/codeql-action/releases/download/codeql-bundle-${CODEQL_VERSION}/codeql-bundle-linux64.tar.gz|tar zx
SAVE ARTIFACT codeql
# ci-codeql is used by CI to build Crossplane with CodeQL scanning enabled.
ci-codeql:
ARG CGO_ENABLED=0
ARG TARGETOS
ARG TARGETARCH
# Using a static CROSSPLANE_VERSION allows Earthly to cache E2E runs as long
# as no code changed. If the version contains a git commit (the default) the
# build layer cache is invalidated on every commit.
FROM +go-modules --CROSSPLANE_VERSION=v0.0.0-codeql
IF [ "${TARGETARCH}" = "arm64" ] && [ "${TARGETOS}" = "linux" ]
RUN --no-cache echo "CodeQL doesn't support Linux on Apple Silicon" && false
END
COPY --dir +ci-codeql-setup/codeql /codeql
CACHE --id go-build --sharing shared /root/.cache/go-build
COPY --dir apis/ pkg/ .
RUN /codeql/codeql database create /codeqldb --language=go
RUN /codeql/codeql database analyze /codeqldb --threads=0 --format=sarif-latest --output=go.sarif --sarif-add-baseline-file-info
SAVE ARTIFACT go.sarif AS LOCAL _output/codeql/go.sarif

View File

@ -1,13 +0,0 @@
# Crossplane-Runtime Setup
## Requirements
An Intel-based machine (recommend 2+ cores, 2+ GB of memory and 128GB of SSD). Inside your build environment (Docker for Mac or a VM), 6+ GB memory is also recommended.
The following tools are need on the host:
- curl
- git
- make
- golang
- kubebuilder (v1.0.4+)

View File

@ -1,94 +0,0 @@
# ====================================================================================
# Setup Project
PROJECT_NAME := crossplane-runtime
PROJECT_REPO := github.com/crossplane/$(PROJECT_NAME)
PLATFORMS ?= linux_amd64 linux_arm64
# -include will silently skip missing files, which allows us
# to load those files with a target in the Makefile. If only
# "include" was used, the make command would fail and refuse
# to run a target until the include commands succeeded.
-include build/makelib/common.mk
# ====================================================================================
# Setup Images
# even though this repo doesn't build images (note the no-op img.build target below),
# some of the init is needed for the cross build container, e.g. setting BUILD_REGISTRY
-include build/makelib/image.mk
img.build:
# ====================================================================================
# Setup Go
# Set a sane default so that the nprocs calculation below is less noisy on the initial
# loading of this file
NPROCS ?= 1
# each of our test suites starts a kube-apiserver and running many test suites in
# parallel can lead to high CPU utilization. by default we reduce the parallelism
# to half the number of CPU cores.
GO_TEST_PARALLEL := $(shell echo $$(( $(NPROCS) / 2 )))
GO_LDFLAGS += -X $(GO_PROJECT)/pkg/version.Version=$(VERSION)
GO_SUBDIRS += pkg apis
GO111MODULE = on
-include build/makelib/golang.mk
# ====================================================================================
# Targets
# run `make help` to see the targets and options
# We want submodules to be set up the first time `make` is run.
# We manage the build/ folder and its Makefiles as a submodule.
# The first time `make` is run, the includes of build/*.mk files will
# all fail, and this target will be run. The next time, the default as defined
# by the includes will be run instead.
fallthrough: submodules
@echo Initial setup complete. Running make again . . .
@make
# Generate a coverage report for cobertura applying exclusions on
# - generated file
cobertura:
@cat $(GO_TEST_OUTPUT)/coverage.txt | \
grep -v zz_generated.deepcopy | \
$(GOCOVER_COBERTURA) > $(GO_TEST_OUTPUT)/cobertura-coverage.xml
# Ensure a PR is ready for review.
reviewable: generate lint
@go mod tidy
# Ensure branch is clean.
check-diff: reviewable
@$(INFO) checking that branch is clean
@git diff --quiet || $(FAIL)
@$(OK) branch is clean
# Update the submodules, such as the common build scripts.
submodules:
@git submodule sync
@git submodule update --init --recursive
.PHONY: cobertura reviewable submodules fallthrough
# ====================================================================================
# Special Targets
define CROSSPLANE_RUNTIME_HELP
Crossplane Runtime Targets:
cobertura Generate a coverage report for cobertura applying exclusions on generated files.
reviewable Ensure a PR is ready for review.
submodules Update the submodules, such as the common build scripts.
endef
export CROSSPLANE_RUNTIME_HELP
crossplane-runtime.help:
@echo "$$CROSSPLANE_RUNTIME_HELP"
help-special: crossplane-runtime.help
.PHONY: crossplane-runtime.help help-special

View File

@ -1,15 +1,30 @@
# OWNERS
# Crossplane Maintainers
This page lists all maintainers for **this** repository. Each repository in the [Crossplane
organization](https://github.com/crossplane/) will list their repository maintainers in their own
`OWNERS.md` file.
This page lists all active maintainers and reviewers for **this** repository.
Each repository in the [Crossplane organization](https://github.com/crossplane/)
will list their repository maintainers and reviewers in their own `OWNERS.md`
file.
Please see [GOVERNANCE.md](https://github.com/crossplane/crossplane/blob/main/GOVERNANCE.md)
for governance guidelines and responsibilities for maintainers, and reviewers.
See [CODEOWNERS](CODEOWNERS) for automatic PR assignment.
Please see the Crossplane
[GOVERNANCE.md](https://github.com/crossplane/crossplane/blob/master/GOVERNANCE.md) for governance
guidelines and responsibilities for the steering committee and maintainers.
## Maintainers
* Nic Cope <negz@upbound.io> ([negz](https://github.com/negz))
* Daniel Mangum <dan@upbound.io> ([hasheddan](https://github.com/hasheddan))
* Muvaffak Onus <monus@upbound.io> ([muvaf](https://github.com/muvaf))
* Hasan Turken <hasan@upbound.io> ([turkenh](https://github.com/turkenh))
* Bob Haddleton <bob.haddleton@nokia.com> ([bobh66](https://github.com/bobh66))
* Philippe Scorsolini <philippe.scorsolini@upbound.io> ([phisco](https://github.com/phisco))
## Reviewers
* Yury Tsarev <yury@upbound.io> ([ytsarev](https://github.com/ytsarev))
* Ezgi Demirel <ezgi@upbound.io> ([ezgidemirel](https://github.com/ezgidemirel))
* Max Blatt ([MisterMX](https://github.com/MisterMX))
## Emeritus maintainers
* Jared Watts <jared@upbound.io> ([jbw976](https://github.com/jbw976))
* Illya Chekrygin <illya.chekrygin@gmail.com> ([ichekrygin](https://github.com/ichekrygin))

View File

@ -1,4 +1,5 @@
# crossplane-runtime [![Godoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/crossplane/crossplane-runtime)
# crossplane-runtime
[![CI](https://github.com/crossplane/crossplane-runtime/actions/workflows/ci.yml/badge.svg)](https://github.com/crossplane/crossplane-runtime/actions/workflows/ci.yml) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/crossplane/crossplane-runtime) [![Godoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://godoc.org/github.com/crossplane/crossplane-runtime)
## Overview
@ -46,15 +47,15 @@ crossplane-runtime is under the Apache 2.0 license.
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fcrossplane%2Fcrossplane-runtime.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fcrossplane%2Fcrossplane-runtime?ref=badge_large)
[developer guide]: https://crossplane.io/docs/master/contributing/overview.html
[developer guide]: https://github.com/crossplane/crossplane/tree/main/contributing
[API documentation]: https://godoc.org/github.com/crossplane/crossplane-runtime
[contributing]: https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md
[contributing]: https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md
[issue]: https://github.com/crossplane/crossplane-runtime/issues
[slack channel]: https://slack.crossplane.io
[crossplane-dev]: https://groups.google.com/forum/#!forum/crossplane-dev
[@crossplane_io]: https://twitter.com/crossplane_io
[info@crossplane.io]: mailto:info@crossplane.io
[roadmap]: https://github.com/crossplane/crossplane/blob/master/ROADMAP.md
[governance]: https://github.com/crossplane/crossplane/blob/master/GOVERNANCE.md
[ownership]: https://github.com/crossplane/crossplane/blob/master/OWNERS.md
[code of conduct]: https://github.com/crossplane/crossplane/blob/master/CODE_OF_CONDUCT.md
[roadmap]: https://github.com/crossplane/crossplane/blob/main/ROADMAP.md
[governance]: https://github.com/crossplane/crossplane/blob/main/GOVERNANCE.md
[ownership]: https://github.com/crossplane/crossplane/blob/main/OWNERS.md
[code of conduct]: https://github.com/crossplane/crossplane/blob/main/CODE_OF_CONDUCT.md

25
RELEASE.md Normal file
View File

@ -0,0 +1,25 @@
# Release Process
## New Patch Release (vX.Y.Z)
In order to cut a new patch release from an existing release branch `release-X.Y`, follow these steps:
- Run the [Tag workflow][tag-workflow] on the `release-X.Y` branch with the proper release version, `vX.Y.Z`. Message suggested, but not required: `Release vX.Y.Z`.
- Draft the [new release notes], and share them with the rest of the team to ensure that all the required information is included.
- Publish the above release notes.
## New Minor Release (vX.Y.0)
In order to cut a new minor release, follow these steps:
- Create a new release branch `release-X.Y` from `main`, using the [GitHub UI][create-branch].
- Create and merge an empty commit to the `main` branch, if required to have it at least one commit ahead of the release branch.
- Run the [Tag workflow][tag-workflow] on the `main` branch with the release candidate tag for the next release, so `vX.<Y+1>.0-rc.0`.
- Run the [Tag workflow][tag-workflow] on the `release-X.Y` branch with the proper release version, `vX.Y.0`. Message suggested, but not required: `Release vX.Y.0`.
- Draft the [new release notes], and share them with the rest of the team to ensure that all the required information is included.
- Publish the above release notes.
<!-- Named Links -->
[create-branch]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-and-deleting-branches-within-your-repository
[new release notes]: https://github.com/crossplane/crossplane-runtime/releases/new
[tag-workflow]: https://github.com/crossplane/crossplane-runtime/actions/workflows/tag.yml

7
SECURITY.md Normal file
View File

@ -0,0 +1,7 @@
# Security Policy
## Reporting a Vulnerability
Instructions for reporting a vulnerability can be found on the
[crossplane repository](https://github.com/crossplane/crossplane/blob/main/SECURITY.md).

View File

@ -1,3 +1,4 @@
//go:build generate
// +build generate
/*
@ -22,9 +23,25 @@ limitations under the License.
// Generate deepcopy methodsets
//go:generate go run -tags generate sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=../hack/boilerplate.go.txt paths=./...
// Generate External Secret Store gRPC types and stubs.
//
// We use buf rather than the traditional protoc because it's pure go and can
// thus be invoked using go run from a pinned dependency. If we used protoc we'd
// need to install it via the Makefile, and there are not currently statically
// compiled binaries available for download (the release binaries for Linux are
// dynamically linked). See buf.gen.yaml for buf's configuration.
//
// We go install the required plugins because they need to be in $PATH for buf
// (or protoc) to invoke them.
//go:generate go install google.golang.org/protobuf/cmd/protoc-gen-go google.golang.org/grpc/cmd/protoc-gen-go-grpc
//go:generate go run github.com/bufbuild/buf/cmd/buf@v1.36.0 generate
// Package apis contains Kubernetes API groups
package apis
import (
_ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" //nolint:typecheck
_ "google.golang.org/protobuf/cmd/protoc-gen-go" //nolint:typecheck
_ "sigs.k8s.io/controller-tools/cmd/controller-gen" //nolint:typecheck
)

10
apis/buf.gen.yaml Normal file
View File

@ -0,0 +1,10 @@
# This file contains configuration for the `buf generate` command.
# See generate.go for more details.
version: v1
plugins:
- plugin: go
out: .
opt: paths=source_relative
- plugin: go-grpc
out: .
opt: paths=source_relative

9
apis/buf.yaml Normal file
View File

@ -0,0 +1,9 @@
version: v1
name: buf.build/crossplane/crossplane-runtime
breaking:
use:
- FILE
lint:
use:
- DEFAULT
allow_comment_ignores: true

View File

@ -0,0 +1,453 @@
//
//Copyright 2024 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.36.5
// protoc (unknown)
// source: changelogs/proto/v1alpha1/changelog.proto
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
package v1alpha1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
structpb "google.golang.org/protobuf/types/known/structpb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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)
)
// OperationType represents the type of operation that was performed on a
// resource.
type OperationType int32
const (
OperationType_OPERATION_TYPE_UNSPECIFIED OperationType = 0
OperationType_OPERATION_TYPE_CREATE OperationType = 1
OperationType_OPERATION_TYPE_UPDATE OperationType = 2
OperationType_OPERATION_TYPE_DELETE OperationType = 3
)
// Enum value maps for OperationType.
var (
OperationType_name = map[int32]string{
0: "OPERATION_TYPE_UNSPECIFIED",
1: "OPERATION_TYPE_CREATE",
2: "OPERATION_TYPE_UPDATE",
3: "OPERATION_TYPE_DELETE",
}
OperationType_value = map[string]int32{
"OPERATION_TYPE_UNSPECIFIED": 0,
"OPERATION_TYPE_CREATE": 1,
"OPERATION_TYPE_UPDATE": 2,
"OPERATION_TYPE_DELETE": 3,
}
)
func (x OperationType) Enum() *OperationType {
p := new(OperationType)
*p = x
return p
}
func (x OperationType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (OperationType) Descriptor() protoreflect.EnumDescriptor {
return file_changelogs_proto_v1alpha1_changelog_proto_enumTypes[0].Descriptor()
}
func (OperationType) Type() protoreflect.EnumType {
return &file_changelogs_proto_v1alpha1_changelog_proto_enumTypes[0]
}
func (x OperationType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use OperationType.Descriptor instead.
func (OperationType) EnumDescriptor() ([]byte, []int) {
return file_changelogs_proto_v1alpha1_changelog_proto_rawDescGZIP(), []int{0}
}
// SendChangeLogRequest represents a request to send a single change log entry.
type SendChangeLogRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The change log entry to send as part of this request.
Entry *ChangeLogEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SendChangeLogRequest) Reset() {
*x = SendChangeLogRequest{}
mi := &file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SendChangeLogRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SendChangeLogRequest) ProtoMessage() {}
func (x *SendChangeLogRequest) ProtoReflect() protoreflect.Message {
mi := &file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SendChangeLogRequest.ProtoReflect.Descriptor instead.
func (*SendChangeLogRequest) Descriptor() ([]byte, []int) {
return file_changelogs_proto_v1alpha1_changelog_proto_rawDescGZIP(), []int{0}
}
func (x *SendChangeLogRequest) GetEntry() *ChangeLogEntry {
if x != nil {
return x.Entry
}
return nil
}
// ChangeLogEntry represents a single change log entry, with detailed information
// about the resource that was changed.
type ChangeLogEntry struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The timestamp at which the change occurred.
Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// The name and version of the provider that is making the change to the
// resource.
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
// The API version of the resource that was changed, e.g. Group/Version.
ApiVersion string `protobuf:"bytes,3,opt,name=api_version,json=apiVersion,proto3" json:"api_version,omitempty"`
// The kind of the resource that was changed.
Kind string `protobuf:"bytes,4,opt,name=kind,proto3" json:"kind,omitempty"`
// The name of the resource that was changed.
Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
// The external name of the resource that was changed.
ExternalName string `protobuf:"bytes,6,opt,name=external_name,json=externalName,proto3" json:"external_name,omitempty"`
// The type of operation that was performed on the resource, e.g. Create,
// Update, or Delete.
Operation OperationType `protobuf:"varint,7,opt,name=operation,proto3,enum=changelogs.proto.v1alpha1.OperationType" json:"operation,omitempty"`
// A full snapshot of the resource's state, as observed directly before the
// resource was changed.
Snapshot *structpb.Struct `protobuf:"bytes,8,opt,name=snapshot,proto3" json:"snapshot,omitempty"`
// An optional error message that describes any error encountered while
// performing the operation on the resource.
ErrorMessage *string `protobuf:"bytes,9,opt,name=error_message,json=errorMessage,proto3,oneof" json:"error_message,omitempty"`
// An optional additional details that can be provided for further context
// about the change.
AdditionalDetails map[string]string `protobuf:"bytes,10,rep,name=additional_details,json=additionalDetails,proto3" json:"additional_details,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ChangeLogEntry) Reset() {
*x = ChangeLogEntry{}
mi := &file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ChangeLogEntry) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ChangeLogEntry) ProtoMessage() {}
func (x *ChangeLogEntry) ProtoReflect() protoreflect.Message {
mi := &file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ChangeLogEntry.ProtoReflect.Descriptor instead.
func (*ChangeLogEntry) Descriptor() ([]byte, []int) {
return file_changelogs_proto_v1alpha1_changelog_proto_rawDescGZIP(), []int{1}
}
func (x *ChangeLogEntry) GetTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.Timestamp
}
return nil
}
func (x *ChangeLogEntry) GetProvider() string {
if x != nil {
return x.Provider
}
return ""
}
func (x *ChangeLogEntry) GetApiVersion() string {
if x != nil {
return x.ApiVersion
}
return ""
}
func (x *ChangeLogEntry) GetKind() string {
if x != nil {
return x.Kind
}
return ""
}
func (x *ChangeLogEntry) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *ChangeLogEntry) GetExternalName() string {
if x != nil {
return x.ExternalName
}
return ""
}
func (x *ChangeLogEntry) GetOperation() OperationType {
if x != nil {
return x.Operation
}
return OperationType_OPERATION_TYPE_UNSPECIFIED
}
func (x *ChangeLogEntry) GetSnapshot() *structpb.Struct {
if x != nil {
return x.Snapshot
}
return nil
}
func (x *ChangeLogEntry) GetErrorMessage() string {
if x != nil && x.ErrorMessage != nil {
return *x.ErrorMessage
}
return ""
}
func (x *ChangeLogEntry) GetAdditionalDetails() map[string]string {
if x != nil {
return x.AdditionalDetails
}
return nil
}
// SendChangeLogResponse is the response returned by the ChangeLogService after
// a change log entry is sent. Currently, this is an empty message as the only
// useful information expected to sent back at this time will be through errors.
type SendChangeLogResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SendChangeLogResponse) Reset() {
*x = SendChangeLogResponse{}
mi := &file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SendChangeLogResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SendChangeLogResponse) ProtoMessage() {}
func (x *SendChangeLogResponse) ProtoReflect() protoreflect.Message {
mi := &file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SendChangeLogResponse.ProtoReflect.Descriptor instead.
func (*SendChangeLogResponse) Descriptor() ([]byte, []int) {
return file_changelogs_proto_v1alpha1_changelog_proto_rawDescGZIP(), []int{2}
}
var File_changelogs_proto_v1alpha1_changelog_proto protoreflect.FileDescriptor
var file_changelogs_proto_v1alpha1_changelog_proto_rawDesc = string([]byte{
0x0a, 0x29, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x63, 0x68, 0x61, 0x6e,
0x67, 0x65, 0x6c, 0x6f, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x63, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31,
0x61, 0x6c, 0x70, 0x68, 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, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x57, 0x0a, 0x14, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a,
0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c,
0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0xc4,
0x04, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x70,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70,
0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c,
0x70, 0x68, 0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79,
0x70, 0x65, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a,
0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x08, 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, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68,
0x6f, 0x74, 0x12, 0x28, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x6f, 0x0a, 0x12,
0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69,
0x6c, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c,
0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x61, 0x64, 0x64, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x44, 0x0a,
0x16, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 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, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x80,
0x01, 0x0a, 0x0d, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65,
0x12, 0x1e, 0x0a, 0x1a, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59,
0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59,
0x50, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x4f,
0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50,
0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54,
0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10,
0x03, 0x32, 0x88, 0x01, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x74, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x68,
0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x67, 0x12, 0x2f, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70,
0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f,
0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c,
0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c,
0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x49, 0x5a, 0x47,
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,
0x2d, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x63, 0x68,
0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
})
var (
file_changelogs_proto_v1alpha1_changelog_proto_rawDescOnce sync.Once
file_changelogs_proto_v1alpha1_changelog_proto_rawDescData []byte
)
func file_changelogs_proto_v1alpha1_changelog_proto_rawDescGZIP() []byte {
file_changelogs_proto_v1alpha1_changelog_proto_rawDescOnce.Do(func() {
file_changelogs_proto_v1alpha1_changelog_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_changelogs_proto_v1alpha1_changelog_proto_rawDesc), len(file_changelogs_proto_v1alpha1_changelog_proto_rawDesc)))
})
return file_changelogs_proto_v1alpha1_changelog_proto_rawDescData
}
var file_changelogs_proto_v1alpha1_changelog_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_changelogs_proto_v1alpha1_changelog_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_changelogs_proto_v1alpha1_changelog_proto_goTypes = []any{
(OperationType)(0), // 0: changelogs.proto.v1alpha1.OperationType
(*SendChangeLogRequest)(nil), // 1: changelogs.proto.v1alpha1.SendChangeLogRequest
(*ChangeLogEntry)(nil), // 2: changelogs.proto.v1alpha1.ChangeLogEntry
(*SendChangeLogResponse)(nil), // 3: changelogs.proto.v1alpha1.SendChangeLogResponse
nil, // 4: changelogs.proto.v1alpha1.ChangeLogEntry.AdditionalDetailsEntry
(*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp
(*structpb.Struct)(nil), // 6: google.protobuf.Struct
}
var file_changelogs_proto_v1alpha1_changelog_proto_depIdxs = []int32{
2, // 0: changelogs.proto.v1alpha1.SendChangeLogRequest.entry:type_name -> changelogs.proto.v1alpha1.ChangeLogEntry
5, // 1: changelogs.proto.v1alpha1.ChangeLogEntry.timestamp:type_name -> google.protobuf.Timestamp
0, // 2: changelogs.proto.v1alpha1.ChangeLogEntry.operation:type_name -> changelogs.proto.v1alpha1.OperationType
6, // 3: changelogs.proto.v1alpha1.ChangeLogEntry.snapshot:type_name -> google.protobuf.Struct
4, // 4: changelogs.proto.v1alpha1.ChangeLogEntry.additional_details:type_name -> changelogs.proto.v1alpha1.ChangeLogEntry.AdditionalDetailsEntry
1, // 5: changelogs.proto.v1alpha1.ChangeLogService.SendChangeLog:input_type -> changelogs.proto.v1alpha1.SendChangeLogRequest
3, // 6: changelogs.proto.v1alpha1.ChangeLogService.SendChangeLog:output_type -> changelogs.proto.v1alpha1.SendChangeLogResponse
6, // [6:7] is the sub-list for method output_type
5, // [5:6] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_changelogs_proto_v1alpha1_changelog_proto_init() }
func file_changelogs_proto_v1alpha1_changelog_proto_init() {
if File_changelogs_proto_v1alpha1_changelog_proto != nil {
return
}
file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[1].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_changelogs_proto_v1alpha1_changelog_proto_rawDesc), len(file_changelogs_proto_v1alpha1_changelog_proto_rawDesc)),
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_changelogs_proto_v1alpha1_changelog_proto_goTypes,
DependencyIndexes: file_changelogs_proto_v1alpha1_changelog_proto_depIdxs,
EnumInfos: file_changelogs_proto_v1alpha1_changelog_proto_enumTypes,
MessageInfos: file_changelogs_proto_v1alpha1_changelog_proto_msgTypes,
}.Build()
File_changelogs_proto_v1alpha1_changelog_proto = out.File
file_changelogs_proto_v1alpha1_changelog_proto_goTypes = nil
file_changelogs_proto_v1alpha1_changelog_proto_depIdxs = nil
}

View File

@ -0,0 +1,88 @@
/*
Copyright 2024 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/timestamp.proto";
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
package changelogs.proto.v1alpha1;
option go_package = "github.com/crossplane/crossplane-runtime/apis/changelogs/proto/v1alpha1";
// ChangeLogService is a service that provides the ability to send change log
// entries.
service ChangeLogService {
// SendChangeLog sends a change log entry to the change log service.
rpc SendChangeLog (SendChangeLogRequest) returns (SendChangeLogResponse) {}
}
// SendChangeLogRequest represents a request to send a single change log entry.
message SendChangeLogRequest {
// The change log entry to send as part of this request.
ChangeLogEntry entry = 1;
}
// ChangeLogEntry represents a single change log entry, with detailed information
// about the resource that was changed.
message ChangeLogEntry {
// The timestamp at which the change occurred.
google.protobuf.Timestamp timestamp = 1;
// The name and version of the provider that is making the change to the
// resource.
string provider = 2;
// The API version of the resource that was changed, e.g. Group/Version.
string api_version = 3;
// The kind of the resource that was changed.
string kind = 4;
// The name of the resource that was changed.
string name = 5;
// The external name of the resource that was changed.
string external_name = 6;
// The type of operation that was performed on the resource, e.g. Create,
// Update, or Delete.
OperationType operation = 7;
// A full snapshot of the resource's state, as observed directly before the
// resource was changed.
google.protobuf.Struct snapshot = 8;
// An optional error message that describes any error encountered while
// performing the operation on the resource.
optional string error_message = 9;
// An optional additional details that can be provided for further context
// about the change.
map<string, string> additional_details = 10;
}
// OperationType represents the type of operation that was performed on a
// resource.
enum OperationType {
OPERATION_TYPE_UNSPECIFIED = 0;
OPERATION_TYPE_CREATE = 1;
OPERATION_TYPE_UPDATE = 2;
OPERATION_TYPE_DELETE = 3;
}
// SendChangeLogResponse is the response returned by the ChangeLogService after
// a change log entry is sent. Currently, this is an empty message as the only
// useful information expected to sent back at this time will be through errors.
message SendChangeLogResponse {}

View File

@ -0,0 +1,125 @@
//
//Copyright 2024 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: changelogs/proto/v1alpha1/changelog.proto
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
package v1alpha1
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 (
ChangeLogService_SendChangeLog_FullMethodName = "/changelogs.proto.v1alpha1.ChangeLogService/SendChangeLog"
)
// ChangeLogServiceClient is the client API for ChangeLogService 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 ChangeLogServiceClient interface {
// SendChangeLog sends a change log entry to the change log service.
SendChangeLog(ctx context.Context, in *SendChangeLogRequest, opts ...grpc.CallOption) (*SendChangeLogResponse, error)
}
type changeLogServiceClient struct {
cc grpc.ClientConnInterface
}
func NewChangeLogServiceClient(cc grpc.ClientConnInterface) ChangeLogServiceClient {
return &changeLogServiceClient{cc}
}
func (c *changeLogServiceClient) SendChangeLog(ctx context.Context, in *SendChangeLogRequest, opts ...grpc.CallOption) (*SendChangeLogResponse, error) {
out := new(SendChangeLogResponse)
err := c.cc.Invoke(ctx, ChangeLogService_SendChangeLog_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ChangeLogServiceServer is the server API for ChangeLogService service.
// All implementations must embed UnimplementedChangeLogServiceServer
// for forward compatibility
type ChangeLogServiceServer interface {
// SendChangeLog sends a change log entry to the change log service.
SendChangeLog(context.Context, *SendChangeLogRequest) (*SendChangeLogResponse, error)
mustEmbedUnimplementedChangeLogServiceServer()
}
// UnimplementedChangeLogServiceServer must be embedded to have forward compatible implementations.
type UnimplementedChangeLogServiceServer struct {
}
func (UnimplementedChangeLogServiceServer) SendChangeLog(context.Context, *SendChangeLogRequest) (*SendChangeLogResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SendChangeLog not implemented")
}
func (UnimplementedChangeLogServiceServer) mustEmbedUnimplementedChangeLogServiceServer() {}
// UnsafeChangeLogServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ChangeLogServiceServer will
// result in compilation errors.
type UnsafeChangeLogServiceServer interface {
mustEmbedUnimplementedChangeLogServiceServer()
}
func RegisterChangeLogServiceServer(s grpc.ServiceRegistrar, srv ChangeLogServiceServer) {
s.RegisterService(&ChangeLogService_ServiceDesc, srv)
}
func _ChangeLogService_SendChangeLog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SendChangeLogRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChangeLogServiceServer).SendChangeLog(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ChangeLogService_SendChangeLog_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChangeLogServiceServer).SendChangeLog(ctx, req.(*SendChangeLogRequest))
}
return interceptor(ctx, in, info, handler)
}
// ChangeLogService_ServiceDesc is the grpc.ServiceDesc for ChangeLogService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ChangeLogService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "changelogs.proto.v1alpha1.ChangeLogService",
HandlerType: (*ChangeLogServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SendChangeLog",
Handler: _ChangeLogService_SendChangeLog_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "changelogs/proto/v1alpha1/changelog.proto",
}

307
apis/common/condition.go Normal file
View File

@ -0,0 +1,307 @@
/*
Copyright 2019 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 common
import (
"sort"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// A ConditionType represents a condition a resource could be in.
type ConditionType string
// Condition types.
const (
// TypeReady resources are believed to be ready to handle work.
TypeReady ConditionType = "Ready"
// TypeSynced resources are believed to be in sync with the
// Kubernetes resources that manage their lifecycle.
TypeSynced ConditionType = "Synced"
// TypeHealthy resources are believed to be in a healthy state and to have all
// of their child resources in a healthy state. For example, a claim is
// healthy when the claim is synced and the underlying composite resource is
// both synced and healthy. A composite resource is healthy when the composite
// resource is synced and all composed resources are synced and, if
// applicable, healthy (e.g., the composed resource is a composite resource).
// TODO: This condition is not yet implemented. It is currently just reserved
// as a system condition. See the tracking issue for more details
// https://github.com/crossplane/crossplane/issues/5643.
TypeHealthy ConditionType = "Healthy"
)
// A ConditionReason represents the reason a resource is in a condition.
type ConditionReason string
// Reasons a resource is or is not ready.
const (
ReasonAvailable ConditionReason = "Available"
ReasonUnavailable ConditionReason = "Unavailable"
ReasonCreating ConditionReason = "Creating"
ReasonDeleting ConditionReason = "Deleting"
)
// Reasons a resource is or is not synced.
const (
ReasonReconcileSuccess ConditionReason = "ReconcileSuccess"
ReasonReconcileError ConditionReason = "ReconcileError"
ReasonReconcilePaused ConditionReason = "ReconcilePaused"
)
// See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
// A Condition that may apply to a resource.
type Condition struct { //nolint:recvcheck // False positive - only has non-pointer methods AFAICT.
// Type of this condition. At most one of each condition type may apply to
// a resource at any point in time.
Type ConditionType `json:"type"`
// Status of this condition; is it currently True, False, or Unknown?
Status corev1.ConditionStatus `json:"status"`
// LastTransitionTime is the last time this condition transitioned from one
// status to another.
LastTransitionTime metav1.Time `json:"lastTransitionTime"`
// A Reason for this condition's last transition from one status to another.
Reason ConditionReason `json:"reason"`
// A Message containing details about this condition's last transition from
// one status to another, if any.
// +optional
Message string `json:"message,omitempty"`
// ObservedGeneration represents the .metadata.generation that the condition was set based upon.
// For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
// with respect to the current state of the instance.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}
// Equal returns true if the condition is identical to the supplied condition,
// ignoring the LastTransitionTime.
func (c Condition) Equal(other Condition) bool {
return c.Type == other.Type &&
c.Status == other.Status &&
c.Reason == other.Reason &&
c.Message == other.Message &&
c.ObservedGeneration == other.ObservedGeneration
}
// WithMessage returns a condition by adding the provided message to existing
// condition.
func (c Condition) WithMessage(msg string) Condition {
c.Message = msg
return c
}
// WithObservedGeneration returns a condition by adding the provided observed generation
// to existing condition.
func (c Condition) WithObservedGeneration(gen int64) Condition {
c.ObservedGeneration = gen
return c
}
// IsSystemConditionType returns true if the condition is owned by the
// Crossplane system (e.g, Ready, Synced, Healthy).
func IsSystemConditionType(t ConditionType) bool {
switch t {
case TypeReady, TypeSynced, TypeHealthy:
return true
}
return false
}
// NOTE(negz): Conditions are implemented as a slice rather than a map to comply
// with Kubernetes API conventions. Ideally we'd comply by using a map that
// marshalled to a JSON array, but doing so confuses the CRD schema generator.
// https://github.com/kubernetes/community/blob/9bf8cd/contributors/devel/sig-architecture/api-conventions.md#lists-of-named-subobjects-preferred-over-maps
// NOTE(negz): Do not manipulate Conditions directly. Use the Set method.
// A ConditionedStatus reflects the observed status of a resource. Only
// one condition of each type may exist.
type ConditionedStatus struct {
// Conditions of the resource.
// +listType=map
// +listMapKey=type
// +optional
Conditions []Condition `json:"conditions,omitempty"`
}
// NewConditionedStatus returns a stat with the supplied conditions set.
func NewConditionedStatus(c ...Condition) *ConditionedStatus {
s := &ConditionedStatus{}
s.SetConditions(c...)
return s
}
// GetCondition returns the condition for the given ConditionType if exists,
// otherwise returns nil.
func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition {
for _, c := range s.Conditions {
if c.Type == ct {
return c
}
}
return Condition{Type: ct, Status: corev1.ConditionUnknown}
}
// SetConditions sets the supplied conditions, replacing any existing conditions
// of the same type. This is a no-op if all supplied conditions are identical,
// ignoring the last transition time, to those already set.
func (s *ConditionedStatus) SetConditions(c ...Condition) {
for _, cond := range c {
exists := false
for i, existing := range s.Conditions {
if existing.Type != cond.Type {
continue
}
if existing.Equal(cond) {
exists = true
continue
}
s.Conditions[i] = cond
exists = true
}
if !exists {
s.Conditions = append(s.Conditions, cond)
}
}
}
// Equal returns true if the status is identical to the supplied status,
// ignoring the LastTransitionTimes and order of statuses.
func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool {
if s == nil || other == nil {
return s == nil && other == nil
}
if len(other.Conditions) != len(s.Conditions) {
return false
}
sc := make([]Condition, len(s.Conditions))
copy(sc, s.Conditions)
oc := make([]Condition, len(other.Conditions))
copy(oc, other.Conditions)
// We should not have more than one condition of each type.
sort.Slice(sc, func(i, j int) bool { return sc[i].Type < sc[j].Type })
sort.Slice(oc, func(i, j int) bool { return oc[i].Type < oc[j].Type })
for i := range sc {
if !sc[i].Equal(oc[i]) {
return false
}
}
return true
}
// Creating returns a condition that indicates the resource is currently
// being created.
func Creating() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonCreating,
}
}
// Deleting returns a condition that indicates the resource is currently
// being deleted.
func Deleting() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonDeleting,
}
}
// Available returns a condition that indicates the resource is
// currently observed to be available for use.
func Available() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: ReasonAvailable,
}
}
// Unavailable returns a condition that indicates the resource is not
// currently available for use. Unavailable should be set only when Crossplane
// expects the resource to be available but knows it is not, for example
// because its API reports it is unhealthy.
func Unavailable() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonUnavailable,
}
}
// ReconcileSuccess returns a condition indicating that Crossplane successfully
// completed the most recent reconciliation of the resource.
func ReconcileSuccess() Condition {
return Condition{
Type: TypeSynced,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: ReasonReconcileSuccess,
}
}
// ReconcileError returns a condition indicating that Crossplane encountered an
// error while reconciling the resource. This could mean Crossplane was
// unable to update the resource to reflect its desired state, or that
// Crossplane was unable to determine the current actual state of the resource.
func ReconcileError(err error) Condition {
return Condition{
Type: TypeSynced,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonReconcileError,
Message: err.Error(),
}
}
// ReconcilePaused returns a condition that indicates reconciliation on
// the managed resource is paused via the pause annotation.
func ReconcilePaused() Condition {
return Condition{
Type: TypeSynced,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonReconcilePaused,
}
}

View File

@ -14,15 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
package common
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
func TestConditionEqual(t *testing.T) {
@ -31,6 +32,25 @@ func TestConditionEqual(t *testing.T) {
b Condition
want bool
}{
"Identical": {
a: Condition{
Type: TypeReady,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: ReasonCreating,
Message: "UnitTest",
ObservedGeneration: 1,
},
b: Condition{
Type: TypeReady,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: ReasonCreating,
Message: "UnitTest",
ObservedGeneration: 1,
},
want: true,
},
"IdenticalIgnoringTimestamp": {
a: Condition{Type: TypeReady, LastTransitionTime: metav1.Now()},
b: Condition{Type: TypeReady, LastTransitionTime: metav1.Now()},
@ -56,6 +76,20 @@ func TestConditionEqual(t *testing.T) {
b: Condition{Message: "uncool"},
want: false,
},
"DifferentObservedGeneration": {
a: Condition{ObservedGeneration: 1},
b: Condition{},
want: false,
},
"CheckReconcilePaused": {
a: ReconcilePaused(),
b: Condition{
Type: TypeSynced,
Status: corev1.ConditionFalse,
Reason: ReasonReconcilePaused,
},
want: true,
},
}
for name, tc := range cases {
@ -129,6 +163,11 @@ func TestSetConditions(t *testing.T) {
c: []Condition{Available()},
want: NewConditionedStatus(Available()),
},
"ObservedGenerationIsUpdated": {
cs: NewConditionedStatus(Available().WithObservedGeneration(1)),
c: []Condition{Available().WithObservedGeneration(2)},
want: NewConditionedStatus(Available().WithObservedGeneration(2)),
},
"TypeIsDifferent": {
cs: NewConditionedStatus(Creating()),
c: []Condition{Available()},
@ -218,3 +257,64 @@ func TestConditionWithMessage(t *testing.T) {
})
}
}
func TestConditionWithObservedGeneration(t *testing.T) {
cases := map[string]struct {
c Condition
observedGeneration int64
want Condition
}{
"Added": {
c: Condition{Type: TypeReady, Reason: ReasonUnavailable},
observedGeneration: 10,
want: Condition{Type: TypeReady, Reason: ReasonUnavailable, ObservedGeneration: 10},
},
"Changed": {
c: Condition{Type: TypeReady, Reason: ReasonUnavailable, ObservedGeneration: 3},
observedGeneration: 10,
want: Condition{Type: TypeReady, Reason: ReasonUnavailable, ObservedGeneration: 10},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := tc.c.WithObservedGeneration(tc.observedGeneration)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("a.Equal(b): -want, +got:\n%s", diff)
}
})
}
}
func TestIsSystemConditionType(t *testing.T) {
cases := map[string]struct {
c Condition
want bool
}{
"SystemReady": {
c: Condition{Type: ConditionType("Ready")},
want: true,
},
"SystemSynced": {
c: Condition{Type: ConditionType("Synced")},
want: true,
},
"SystemHealthy": {
c: Condition{Type: ConditionType("Healthy")},
want: true,
},
"Custom": {
c: Condition{Type: ConditionType("Custom")},
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
if diff := cmp.Diff(tc.want, IsSystemConditionType(tc.c.Type)); diff != "" {
t.Errorf("IsSystemConditionType(tc.c.Type): -want, +got:\n%s", diff)
}
})
}
}

3
apis/common/doc.go Normal file
View File

@ -0,0 +1,3 @@
// Package common contains core API types used by most Crossplane resources.
// +kubebuilder:object:generate=true
package common

54
apis/common/merge.go Normal file
View File

@ -0,0 +1,54 @@
/*
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.
*/
package common
import (
"dario.cat/mergo"
)
// MergeOptions Specifies merge options on a field path.
type MergeOptions struct { // TODO(aru): add more options that control merging behavior
// Specifies that already existing values in a merged map should be preserved
// +optional
KeepMapValues *bool `json:"keepMapValues,omitempty"`
// Specifies that already existing elements in a merged slice should be preserved
// +optional
AppendSlice *bool `json:"appendSlice,omitempty"`
}
// MergoConfiguration the default behavior is to replace maps and slices.
func (mo *MergeOptions) MergoConfiguration() []func(*mergo.Config) {
config := []func(*mergo.Config){mergo.WithOverride}
if mo == nil {
return config
}
if mo.KeepMapValues != nil && *mo.KeepMapValues {
config = config[:0]
}
if mo.AppendSlice != nil && *mo.AppendSlice {
config = append(config, mergo.WithAppendSlice)
}
return config
}
// IsAppendSlice returns true if mo.AppendSlice is set to true.
func (mo *MergeOptions) IsAppendSlice() bool {
return mo != nil && mo.AppendSlice != nil && *mo.AppendSlice
}

92
apis/common/merge_test.go Normal file
View File

@ -0,0 +1,92 @@
/*
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.
*/
package common
import (
"reflect"
"runtime"
"sort"
"testing"
"dario.cat/mergo"
"github.com/google/go-cmp/cmp"
)
type mergoOptArr []func(*mergo.Config)
func (arr mergoOptArr) names() []string {
names := make([]string, len(arr))
for i, opt := range arr {
names[i] = runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name()
}
sort.Strings(names)
return names
}
func TestMergoConfiguration(t *testing.T) {
valTrue := true
tests := map[string]struct {
mo *MergeOptions
want mergoOptArr
}{
"DefaultOptionsNil": {
want: mergoOptArr{
mergo.WithOverride,
},
},
"DefaultOptionsEmptyStruct": {
mo: &MergeOptions{},
want: mergoOptArr{
mergo.WithOverride,
},
},
"MapKeepOnly": {
mo: &MergeOptions{
KeepMapValues: &valTrue,
},
want: mergoOptArr{},
},
"AppendSliceOnly": {
mo: &MergeOptions{
AppendSlice: &valTrue,
},
want: mergoOptArr{
mergo.WithAppendSlice,
mergo.WithOverride,
},
},
"MapKeepAppendSlice": {
mo: &MergeOptions{
AppendSlice: &valTrue,
KeepMapValues: &valTrue,
},
want: mergoOptArr{
mergo.WithAppendSlice,
},
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
if diff := cmp.Diff(tc.want.names(), mergoOptArr(tc.mo.MergoConfiguration()).names()); diff != "" {
t.Errorf("\nmo.MergoConfiguration(): -want, +got:\n %s", diff)
}
})
}
}

View File

@ -0,0 +1,37 @@
/*
Copyright 2024 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 common
// ObservedStatus contains the recent reconciliation stats.
type ObservedStatus struct {
// ObservedGeneration is the latest metadata.generation
// which resulted in either a ready state, or stalled due to error
// it can not recover from without human intervention.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}
// SetObservedGeneration sets the generation of the main resource
// during the last reconciliation.
func (s *ObservedStatus) SetObservedGeneration(generation int64) {
s.ObservedGeneration = generation
}
// GetObservedGeneration returns the last observed generation of the main resource.
func (s *ObservedStatus) GetObservedGeneration() int64 {
return s.ObservedGeneration
}

120
apis/common/policies.go Normal file
View File

@ -0,0 +1,120 @@
/*
Copyright 2019 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 common
// ManagementPolicies determine how should Crossplane controllers manage an
// external resource through an array of ManagementActions.
type ManagementPolicies []ManagementAction
// A ManagementAction represents an action that the Crossplane controllers
// can take on an external resource.
// +kubebuilder:validation:Enum=Observe;Create;Update;Delete;LateInitialize;*
type ManagementAction string
const (
// ManagementActionObserve means that the managed resource status.atProvider
// will be updated with the external resource state.
ManagementActionObserve ManagementAction = "Observe"
// ManagementActionCreate means that the external resource will be created
// using the managed resource spec.initProvider and spec.forProvider.
ManagementActionCreate ManagementAction = "Create"
// ManagementActionUpdate means that the external resource will be updated
// using the managed resource spec.forProvider.
ManagementActionUpdate ManagementAction = "Update"
// ManagementActionDelete means that the external resource will be deleted
// when the managed resource is deleted.
ManagementActionDelete ManagementAction = "Delete"
// ManagementActionLateInitialize means that unspecified fields of the managed
// resource spec.forProvider will be updated with the external resource state.
ManagementActionLateInitialize ManagementAction = "LateInitialize"
// ManagementActionAll means that all of the above actions will be taken
// by the Crossplane controllers.
ManagementActionAll ManagementAction = "*"
)
// A DeletionPolicy determines what should happen to the underlying external
// resource when a managed resource is deleted.
// +kubebuilder:validation:Enum=Orphan;Delete
type DeletionPolicy string
const (
// DeletionOrphan means the external resource will be orphaned when its
// managed resource is deleted.
DeletionOrphan DeletionPolicy = "Orphan"
// DeletionDelete means both the external resource will be deleted when its
// managed resource is deleted.
DeletionDelete DeletionPolicy = "Delete"
)
// A CompositeDeletePolicy determines how the composite resource should be deleted
// when the corresponding claim is deleted.
// +kubebuilder:validation:Enum=Background;Foreground
type CompositeDeletePolicy string
const (
// CompositeDeleteBackground means the composite resource will be deleted using
// the Background Propagation Policy when the claim is deleted.
CompositeDeleteBackground CompositeDeletePolicy = "Background"
// CompositeDeleteForeground means the composite resource will be deleted using
// the Foreground Propagation Policy when the claim is deleted.
CompositeDeleteForeground CompositeDeletePolicy = "Foreground"
)
// An UpdatePolicy determines how something should be updated - either
// automatically (without human intervention) or manually.
// +kubebuilder:validation:Enum=Automatic;Manual
type UpdatePolicy string
const (
// UpdateAutomatic means the resource should be updated automatically,
// without any human intervention.
UpdateAutomatic UpdatePolicy = "Automatic"
// UpdateManual means the resource requires human intervention to
// update.
UpdateManual UpdatePolicy = "Manual"
)
// ResolvePolicy is a type for resolve policy.
type ResolvePolicy string
// ResolutionPolicy is a type for resolution policy.
type ResolutionPolicy string
const (
// ResolvePolicyAlways is a resolve option.
// When the ResolvePolicy is set to ResolvePolicyAlways the reference will
// be tried to resolve for every reconcile loop.
ResolvePolicyAlways ResolvePolicy = "Always"
// ResolutionPolicyRequired is a resolution option.
// When the ResolutionPolicy is set to ResolutionPolicyRequired the execution
// could not continue even if the reference cannot be resolved.
ResolutionPolicyRequired ResolutionPolicy = "Required"
// ResolutionPolicyOptional is a resolution option.
// When the ReferenceResolutionPolicy is set to ReferencePolicyOptional the
// execution could continue even if the reference cannot be resolved.
ResolutionPolicyOptional ResolutionPolicy = "Optional"
)

328
apis/common/resource.go Normal file
View File

@ -0,0 +1,328 @@
/*
Copyright 2019 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 common
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
)
const (
// ResourceCredentialsSecretEndpointKey is the key inside a connection secret for the connection endpoint.
ResourceCredentialsSecretEndpointKey = "endpoint"
// ResourceCredentialsSecretPortKey is the key inside a connection secret for the connection port.
ResourceCredentialsSecretPortKey = "port"
// ResourceCredentialsSecretUserKey is the key inside a connection secret for the connection user.
ResourceCredentialsSecretUserKey = "username"
// ResourceCredentialsSecretPasswordKey is the key inside a connection secret for the connection password.
ResourceCredentialsSecretPasswordKey = "password"
// ResourceCredentialsSecretCAKey is the key inside a connection secret for the server CA certificate.
ResourceCredentialsSecretCAKey = "clusterCA"
// ResourceCredentialsSecretClientCertKey is the key inside a connection secret for the client certificate.
ResourceCredentialsSecretClientCertKey = "clientCert"
// ResourceCredentialsSecretClientKeyKey is the key inside a connection secret for the client key.
ResourceCredentialsSecretClientKeyKey = "clientKey"
// ResourceCredentialsSecretTokenKey is the key inside a connection secret for the bearer token value.
ResourceCredentialsSecretTokenKey = "token"
// ResourceCredentialsSecretKubeconfigKey is the key inside a connection secret for the raw kubeconfig yaml.
ResourceCredentialsSecretKubeconfigKey = "kubeconfig"
)
// LabelKeyProviderKind is added to ProviderConfigUsages to relate them to their
// ProviderConfig.
const LabelKeyProviderKind = "crossplane.io/provider-config-kind"
// LabelKeyProviderName is added to ProviderConfigUsages to relate them to their
// ProviderConfig.
const LabelKeyProviderName = "crossplane.io/provider-config"
// NOTE(negz): The below secret references differ from ObjectReference and
// LocalObjectReference in that they include only the fields Crossplane needs to
// reference a secret, and make those fields required. This reduces ambiguity in
// the API for resource authors.
// A LocalSecretReference is a reference to a secret in the same namespace as
// the referencer.
type LocalSecretReference struct {
// Name of the secret.
Name string `json:"name"`
}
// A SecretReference is a reference to a secret in an arbitrary namespace.
type SecretReference struct {
// Name of the secret.
Name string `json:"name"`
// Namespace of the secret.
Namespace string `json:"namespace"`
}
// A SecretKeySelector is a reference to a secret key in an arbitrary namespace.
type SecretKeySelector struct {
SecretReference `json:",inline"`
// The key to select.
Key string `json:"key"`
}
// A LocalSecretKeySelector is a reference to a secret key
// in the same namespace with the referencing object.
type LocalSecretKeySelector struct {
LocalSecretReference `json:",inline"`
Key string `json:"key"`
}
// ToSecretKeySelector is a convenience method for converting the
// LocalSecretKeySelector to a SecretKeySelector with the given namespace.
func (ls *LocalSecretKeySelector) ToSecretKeySelector(namespace string) *SecretKeySelector {
return &SecretKeySelector{
SecretReference: SecretReference{
Name: ls.Name,
Namespace: namespace,
},
Key: ls.Key,
}
}
// Policy represents the Resolve and Resolution policies of Reference instance.
type Policy struct {
// 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.
// +optional
// +kubebuilder:validation:Enum=Always;IfNotPresent
Resolve *ResolvePolicy `json:"resolve,omitempty"`
// 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.
// +optional
// +kubebuilder:default=Required
// +kubebuilder:validation:Enum=Required;Optional
Resolution *ResolutionPolicy `json:"resolution,omitempty"`
}
// IsResolutionPolicyOptional checks whether the resolution policy of relevant reference is Optional.
func (p *Policy) IsResolutionPolicyOptional() bool {
if p == nil || p.Resolution == nil {
return false
}
return *p.Resolution == ResolutionPolicyOptional
}
// IsResolvePolicyAlways checks whether the resolution policy of relevant reference is Always.
func (p *Policy) IsResolvePolicyAlways() bool {
if p == nil || p.Resolve == nil {
return false
}
return *p.Resolve == ResolvePolicyAlways
}
// A Reference to a named object.
type Reference struct {
// Name of the referenced object.
Name string `json:"name"`
// Policies for referencing.
// +optional
Policy *Policy `json:"policy,omitempty"`
}
// A NamespacedReference to a named object.
type NamespacedReference struct {
// Name of the referenced object.
Name string `json:"name"`
// Namespace of the referenced object
// +optional
Namespace string `json:"namespace,omitempty"`
// Policies for referencing.
// +optional
Policy *Policy `json:"policy,omitempty"`
}
// 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.
type TypedReference struct {
// APIVersion of the referenced object.
APIVersion string `json:"apiVersion"`
// Kind of the referenced object.
Kind string `json:"kind"`
// Name of the referenced object.
Name string `json:"name"`
// UID of the referenced object.
// +optional
UID types.UID `json:"uid,omitempty"`
}
// A Selector selects an object.
type Selector struct {
// MatchLabels ensures an object with matching labels is selected.
MatchLabels map[string]string `json:"matchLabels,omitempty"`
// MatchControllerRef ensures an object with the same controller reference
// as the selecting object is selected.
MatchControllerRef *bool `json:"matchControllerRef,omitempty"`
// Policies for selection.
// +optional
Policy *Policy `json:"policy,omitempty"`
}
// NamespacedSelector selects a namespaced object.
type NamespacedSelector struct {
// MatchLabels ensures an object with matching labels is selected.
MatchLabels map[string]string `json:"matchLabels,omitempty"`
// MatchControllerRef ensures an object with the same controller reference
// as the selecting object is selected.
MatchControllerRef *bool `json:"matchControllerRef,omitempty"`
// Policies for selection.
// +optional
Policy *Policy `json:"policy,omitempty"`
// Namespace for the selector
// +optional
Namespace string `json:"namespace,omitempty"`
}
// ProviderConfigReference is a typed reference to a ProviderConfig
// object, with a known api group.
type ProviderConfigReference struct {
// Kind of the referenced object.
Kind string `json:"kind"`
// Name of the referenced object.
Name string `json:"name"`
}
// SetGroupVersionKind sets the Kind and APIVersion of a TypedReference.
func (obj *TypedReference) SetGroupVersionKind(gvk schema.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
}
// GroupVersionKind gets the GroupVersionKind of a TypedReference.
func (obj *TypedReference) GroupVersionKind() schema.GroupVersionKind {
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
}
// GetObjectKind get the ObjectKind of a TypedReference.
func (obj *TypedReference) GetObjectKind() schema.ObjectKind { return obj }
// ResourceStatus represents the observed state of a managed resource.
type ResourceStatus struct {
ConditionedStatus `json:",inline"`
ObservedStatus `json:",inline"`
}
// A CredentialsSource is a source from which provider credentials may be
// acquired.
type CredentialsSource string
const (
// CredentialsSourceNone indicates that a provider does not require
// credentials.
CredentialsSourceNone CredentialsSource = "None"
// CredentialsSourceSecret indicates that a provider should acquire
// credentials from a secret.
CredentialsSourceSecret CredentialsSource = "Secret"
// CredentialsSourceInjectedIdentity indicates that a provider should use
// credentials via its (pod's) identity; i.e. via IRSA for AWS,
// Workload Identity for GCP, Pod Identity for Azure, or in-cluster
// authentication for the Kubernetes API.
CredentialsSourceInjectedIdentity CredentialsSource = "InjectedIdentity"
// CredentialsSourceEnvironment indicates that a provider should acquire
// credentials from an environment variable.
CredentialsSourceEnvironment CredentialsSource = "Environment"
// CredentialsSourceFilesystem indicates that a provider should acquire
// credentials from the filesystem.
CredentialsSourceFilesystem CredentialsSource = "Filesystem"
)
// CommonCredentialSelectors provides common selectors for extracting
// credentials.
//
//nolint:revive // preserve backward-compatibility
type CommonCredentialSelectors struct {
// Fs is a reference to a filesystem location that contains credentials that
// must be used to connect to the provider.
// +optional
Fs *FsSelector `json:"fs,omitempty"`
// Env is a reference to an environment variable that contains credentials
// that must be used to connect to the provider.
// +optional
Env *EnvSelector `json:"env,omitempty"`
// A SecretRef is a reference to a secret key that contains the credentials
// that must be used to connect to the provider.
// +optional
SecretRef *SecretKeySelector `json:"secretRef,omitempty"`
}
// EnvSelector selects an environment variable.
type EnvSelector struct {
// Name is the name of an environment variable.
Name string `json:"name"`
}
// FsSelector selects a filesystem location.
type FsSelector struct {
// Path is a filesystem path.
Path string `json:"path"`
}
// A ProviderConfigStatus defines the observed status of a ProviderConfig.
type ProviderConfigStatus struct {
ConditionedStatus `json:",inline"`
// Users of this provider configuration.
Users int64 `json:"users,omitempty"`
}
// A ProviderConfigUsage is a record that a particular managed resource is using
// a particular provider configuration.
type ProviderConfigUsage struct {
// ProviderConfigReference to the provider config being used.
ProviderConfigReference Reference `json:"providerConfigRef"`
// ResourceReference to the managed resource using the provider config.
ResourceReference TypedReference `json:"resourceRef"`
}
// A TypedProviderConfigUsage is a record that a particular managed resource is using
// a particular provider configuration.
type TypedProviderConfigUsage struct {
// ProviderConfigReference to the provider config being used.
ProviderConfigReference ProviderConfigReference `json:"providerConfigRef"`
// ResourceReference to the managed resource using the provider config.
ResourceReference TypedReference `json:"resourceRef"`
}

View File

@ -17,78 +17,60 @@ limitations under the License.
package v1
import (
"sort"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/crossplane/crossplane-runtime/apis/common"
)
// A ConditionType represents a condition a resource could be in.
type ConditionType string
type ConditionType = common.ConditionType
// Condition types.
const (
// TypeReady resources are believed to be ready to handle work.
TypeReady ConditionType = "Ready"
TypeReady ConditionType = common.TypeReady
// TypeSynced resources are believed to be in sync with the
// Kubernetes resources that manage their lifecycle.
TypeSynced ConditionType = "Synced"
TypeSynced ConditionType = common.TypeSynced
// TypeHealthy resources are believed to be in a healthy state and to have all
// of their child resources in a healthy state. For example, a claim is
// healthy when the claim is synced and the underlying composite resource is
// both synced and healthy. A composite resource is healthy when the composite
// resource is synced and all composed resources are synced and, if
// applicable, healthy (e.g., the composed resource is a composite resource).
// TODO: This condition is not yet implemented. It is currently just reserved
// as a system condition. See the tracking issue for more details
// https://github.com/crossplane/crossplane/issues/5643.
TypeHealthy ConditionType = common.TypeHealthy
)
// A ConditionReason represents the reason a resource is in a condition.
type ConditionReason string
type ConditionReason = common.ConditionReason
// Reasons a resource is or is not ready.
const (
ReasonAvailable ConditionReason = "Available"
ReasonUnavailable ConditionReason = "Unavailable"
ReasonCreating ConditionReason = "Creating"
ReasonDeleting ConditionReason = "Deleting"
ReasonAvailable = common.ReasonAvailable
ReasonUnavailable = common.ReasonUnavailable
ReasonCreating = common.ReasonCreating
ReasonDeleting = common.ReasonDeleting
)
// Reasons a resource is or is not synced.
const (
ReasonReconcileSuccess ConditionReason = "ReconcileSuccess"
ReasonReconcileError ConditionReason = "ReconcileError"
ReasonReconcileSuccess = common.ReasonReconcileSuccess
ReasonReconcileError = common.ReasonReconcileError
ReasonReconcilePaused = common.ReasonReconcilePaused
)
// See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
// A Condition that may apply to a resource.
type Condition struct {
// Type of this condition. At most one of each condition type may apply to
// a resource at any point in time.
Type ConditionType `json:"type"`
type Condition = common.Condition
// Status of this condition; is it currently True, False, or Unknown?
Status corev1.ConditionStatus `json:"status"`
// LastTransitionTime is the last time this condition transitioned from one
// status to another.
LastTransitionTime metav1.Time `json:"lastTransitionTime"`
// A Reason for this condition's last transition from one status to another.
Reason ConditionReason `json:"reason"`
// A Message containing details about this condition's last transition from
// one status to another, if any.
// +optional
Message string `json:"message,omitempty"`
}
// Equal returns true if the condition is identical to the supplied condition,
// ignoring the LastTransitionTime.
func (c Condition) Equal(other Condition) bool {
return c.Type == other.Type &&
c.Status == other.Status &&
c.Reason == other.Reason &&
c.Message == other.Message
}
// WithMessage returns a condition by adding the provided message to existing
// condition.
func (c Condition) WithMessage(msg string) Condition {
c.Message = msg
return c
// IsSystemConditionType returns true if the condition is owned by the
// Crossplane system (e.g, Ready, Synced, Healthy).
func IsSystemConditionType(t ConditionType) bool {
return common.IsSystemConditionType(t)
}
// NOTE(negz): Conditions are implemented as a slice rather than a map to comply
@ -100,117 +82,29 @@ func (c Condition) WithMessage(msg string) Condition {
// A ConditionedStatus reflects the observed status of a resource. Only
// one condition of each type may exist.
type ConditionedStatus struct {
// Conditions of the resource.
// +optional
Conditions []Condition `json:"conditions,omitempty"`
}
type ConditionedStatus = common.ConditionedStatus
// NewConditionedStatus returns a stat with the supplied conditions set.
func NewConditionedStatus(c ...Condition) *ConditionedStatus {
s := &ConditionedStatus{}
s.SetConditions(c...)
return s
}
// GetCondition returns the condition for the given ConditionType if exists,
// otherwise returns nil
func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition {
for _, c := range s.Conditions {
if c.Type == ct {
return c
}
}
return Condition{Type: ct, Status: corev1.ConditionUnknown}
}
// SetConditions sets the supplied conditions, replacing any existing conditions
// of the same type. This is a no-op if all supplied conditions are identical,
// ignoring the last transition time, to those already set.
func (s *ConditionedStatus) SetConditions(c ...Condition) {
for _, new := range c {
exists := false
for i, existing := range s.Conditions {
if existing.Type != new.Type {
continue
}
if existing.Equal(new) {
exists = true
continue
}
s.Conditions[i] = new
exists = true
}
if !exists {
s.Conditions = append(s.Conditions, new)
}
}
}
// Equal returns true if the status is identical to the supplied status,
// ignoring the LastTransitionTimes and order of statuses.
func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool {
if s == nil || other == nil {
return s == nil && other == nil
}
if len(other.Conditions) != len(s.Conditions) {
return false
}
sc := make([]Condition, len(s.Conditions))
copy(sc, s.Conditions)
oc := make([]Condition, len(other.Conditions))
copy(oc, other.Conditions)
// We should not have more than one condition of each type.
sort.Slice(sc, func(i, j int) bool { return sc[i].Type < sc[j].Type })
sort.Slice(oc, func(i, j int) bool { return oc[i].Type < oc[j].Type })
for i := range sc {
if !sc[i].Equal(oc[i]) {
return false
}
}
return true
return common.NewConditionedStatus(c...)
}
// Creating returns a condition that indicates the resource is currently
// being created.
func Creating() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonCreating,
}
return common.Creating()
}
// Deleting returns a condition that indicates the resource is currently
// being deleted.
func Deleting() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonDeleting,
}
return common.Deleting()
}
// Available returns a condition that indicates the resource is
// currently observed to be available for use.
func Available() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: ReasonAvailable,
}
return common.Available()
}
// Unavailable returns a condition that indicates the resource is not
@ -218,23 +112,13 @@ func Available() Condition {
// expects the resource to be available but knows it is not, for example
// because its API reports it is unhealthy.
func Unavailable() Condition {
return Condition{
Type: TypeReady,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonUnavailable,
}
return common.Unavailable()
}
// ReconcileSuccess returns a condition indicating that Crossplane successfully
// completed the most recent reconciliation of the resource.
func ReconcileSuccess() Condition {
return Condition{
Type: TypeSynced,
Status: corev1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: ReasonReconcileSuccess,
}
return common.ReconcileSuccess()
}
// ReconcileError returns a condition indicating that Crossplane encountered an
@ -242,11 +126,11 @@ func ReconcileSuccess() Condition {
// unable to update the resource to reflect its desired state, or that
// Crossplane was unable to determine the current actual state of the resource.
func ReconcileError(err error) Condition {
return Condition{
Type: TypeSynced,
Status: corev1.ConditionFalse,
LastTransitionTime: metav1.Now(),
Reason: ReasonReconcileError,
Message: err.Error(),
}
return common.ReconcileError(err)
}
// ReconcilePaused returns a condition that indicates reconciliation on
// the managed resource is paused via the pause annotation.
func ReconcilePaused() Condition {
return common.ReconcilePaused()
}

View File

@ -14,23 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package ratelimiter
package v1
import (
"testing"
"time"
"github.com/crossplane/crossplane-runtime/apis/common"
)
func TestDefaultMangedRateLimiter(t *testing.T) {
limiter := NewDefaultManagedRateLimiter(NewDefaultProviderRateLimiter(DefaultProviderRPS))
backoffSchedule := []int{1, 2, 4, 8, 16, 32, 60}
for _, d := range backoffSchedule {
if e, a := time.Duration(d)*time.Second, limiter.When("one"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
limiter.Forget("one")
if e, a := time.Duration(backoffSchedule[0])*time.Second, limiter.When("one"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
// MergeOptions Specifies merge options on a field path.
type MergeOptions = common.MergeOptions

View File

@ -0,0 +1,24 @@
/*
Copyright 2024 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 v1
import (
"github.com/crossplane/crossplane-runtime/apis/common"
)
// ObservedStatus contains the recent reconciliation stats.
type ObservedStatus = common.ObservedStatus

View File

@ -16,17 +16,106 @@ limitations under the License.
package v1
import (
"github.com/crossplane/crossplane-runtime/apis/common"
)
// ManagementPolicies determine how should Crossplane controllers manage an
// external resource through an array of ManagementActions.
type ManagementPolicies = common.ManagementPolicies
// A ManagementAction represents an action that the Crossplane controllers
// can take on an external resource.
type ManagementAction = common.ManagementAction
const (
// ManagementActionObserve means that the managed resource status.atProvider
// will be updated with the external resource state.
ManagementActionObserve = common.ManagementActionObserve
// ManagementActionCreate means that the external resource will be created
// using the managed resource spec.initProvider and spec.forProvider.
ManagementActionCreate = common.ManagementActionCreate
// ManagementActionUpdate means that the external resource will be updated
// using the managed resource spec.forProvider.
ManagementActionUpdate = common.ManagementActionUpdate
// ManagementActionDelete means that the external resource will be deleted
// when the managed resource is deleted.
ManagementActionDelete = common.ManagementActionDelete
// ManagementActionLateInitialize means that unspecified fields of the managed
// resource spec.forProvider will be updated with the external resource state.
ManagementActionLateInitialize = common.ManagementActionLateInitialize
// ManagementActionAll means that all of the above actions will be taken
// by the Crossplane controllers.
ManagementActionAll = common.ManagementActionAll
)
// A DeletionPolicy determines what should happen to the underlying external
// resource when a managed resource is deleted.
// +kubebuilder:validation:Enum=Orphan;Delete
type DeletionPolicy string
const (
// DeletionOrphan means the external resource will orphaned when its managed
// resource is deleted.
// DeletionOrphan means the external resource will be orphaned when its
// managed resource is deleted.
DeletionOrphan DeletionPolicy = "Orphan"
// DeletionDelete means both the external resource will be deleted when its
// managed resource is deleted.
DeletionDelete DeletionPolicy = "Delete"
)
// A CompositeDeletePolicy determines how the composite resource should be deleted
// when the corresponding claim is deleted.
type CompositeDeletePolicy = common.CompositeDeletePolicy
const (
// CompositeDeleteBackground means the composite resource will be deleted using
// the Background Propagation Policy when the claim is deleted.
CompositeDeleteBackground = common.CompositeDeleteBackground
// CompositeDeleteForeground means the composite resource will be deleted using
// the Foreground Propagation Policy when the claim is deleted.
CompositeDeleteForeground = common.CompositeDeleteForeground
)
// An UpdatePolicy determines how something should be updated - either
// automatically (without human intervention) or manually.
type UpdatePolicy = common.UpdatePolicy
const (
// UpdateAutomatic means the resource should be updated automatically,
// without any human intervention.
UpdateAutomatic = common.UpdateAutomatic
// UpdateManual means the resource requires human intervention to
// update.
UpdateManual = common.UpdateManual
)
// ResolvePolicy is a type for resolve policy.
type ResolvePolicy = common.ResolvePolicy
// ResolutionPolicy is a type for resolution policy.
type ResolutionPolicy = common.ResolutionPolicy
const (
// ResolvePolicyAlways is a resolve option.
// When the ResolvePolicy is set to ResolvePolicyAlways the reference will
// be tried to resolve for every reconcile loop.
ResolvePolicyAlways = common.ResolvePolicyAlways
// ResolutionPolicyRequired is a resolution option.
// When the ResolutionPolicy is set to ResolutionPolicyRequired the execution
// could not continue even if the reference cannot be resolved.
ResolutionPolicyRequired = common.ResolutionPolicyRequired
// ResolutionPolicyOptional is a resolution option.
// When the ReferenceResolutionPolicy is set to ReferencePolicyOptional the
// execution could continue even if the reference cannot be resolved.
ResolutionPolicyOptional = common.ResolutionPolicyOptional
)

View File

@ -19,34 +19,37 @@ package v1
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"github.com/crossplane/crossplane-runtime/apis/common"
)
const (
// ResourceCredentialsSecretEndpointKey is the key inside a connection secret for the connection endpoint
// ResourceCredentialsSecretEndpointKey is the key inside a connection secret for the connection endpoint.
ResourceCredentialsSecretEndpointKey = "endpoint"
// ResourceCredentialsSecretPortKey is the key inside a connection secret for the connection port
// ResourceCredentialsSecretPortKey is the key inside a connection secret for the connection port.
ResourceCredentialsSecretPortKey = "port"
// ResourceCredentialsSecretUserKey is the key inside a connection secret for the connection user
// ResourceCredentialsSecretUserKey is the key inside a connection secret for the connection user.
ResourceCredentialsSecretUserKey = "username"
// ResourceCredentialsSecretPasswordKey is the key inside a connection secret for the connection password
// ResourceCredentialsSecretPasswordKey is the key inside a connection secret for the connection password.
ResourceCredentialsSecretPasswordKey = "password"
// ResourceCredentialsSecretCAKey is the key inside a connection secret for the server CA certificate
// ResourceCredentialsSecretCAKey is the key inside a connection secret for the server CA certificate.
ResourceCredentialsSecretCAKey = "clusterCA"
// ResourceCredentialsSecretClientCertKey is the key inside a connection secret for the client certificate
// ResourceCredentialsSecretClientCertKey is the key inside a connection secret for the client certificate.
ResourceCredentialsSecretClientCertKey = "clientCert"
// ResourceCredentialsSecretClientKeyKey is the key inside a connection secret for the client key
// ResourceCredentialsSecretClientKeyKey is the key inside a connection secret for the client key.
ResourceCredentialsSecretClientKeyKey = "clientKey"
// ResourceCredentialsSecretTokenKey is the key inside a connection secret for the bearer token value
// ResourceCredentialsSecretTokenKey is the key inside a connection secret for the bearer token value.
ResourceCredentialsSecretTokenKey = "token"
// ResourceCredentialsSecretKubeconfigKey is the key inside a connection secret for the raw kubeconfig yaml
// ResourceCredentialsSecretKubeconfigKey is the key inside a connection secret for the raw kubeconfig yaml.
ResourceCredentialsSecretKubeconfigKey = "kubeconfig"
)
// LabelKeyProviderKind is added to ProviderConfigUsages to relate them to their
// ProviderConfig.
const LabelKeyProviderKind = common.LabelKeyProviderKind
// LabelKeyProviderName is added to ProviderConfigUsages to relate them to their
// ProviderConfig.
const LabelKeyProviderName = "crossplane.io/provider-config"
const LabelKeyProviderName = common.LabelKeyProviderName
// NOTE(negz): The below secret references differ from ObjectReference and
// LocalObjectReference in that they include only the fields Crossplane needs to
@ -55,74 +58,41 @@ const LabelKeyProviderName = "crossplane.io/provider-config"
// A LocalSecretReference is a reference to a secret in the same namespace as
// the referencer.
type LocalSecretReference struct {
// Name of the secret.
Name string `json:"name"`
}
type LocalSecretReference = common.LocalSecretReference
// A SecretReference is a reference to a secret in an arbitrary namespace.
type SecretReference struct {
// Name of the secret.
Name string `json:"name"`
// Namespace of the secret.
Namespace string `json:"namespace"`
}
type SecretReference = common.SecretReference
// A SecretKeySelector is a reference to a secret key in an arbitrary namespace.
type SecretKeySelector struct {
SecretReference `json:",inline"`
type SecretKeySelector = common.SecretKeySelector
// The key to select.
Key string `json:"key"`
}
// A LocalSecretKeySelector is a reference to a secret key
// in the same namespace with the referencing object.
type LocalSecretKeySelector = common.LocalSecretKeySelector
// Policy represents the Resolve and Resolution policies of Reference instance.
type Policy = common.Policy
// A Reference to a named object.
type Reference struct {
// Name of the referenced object.
Name string `json:"name"`
}
type Reference = common.Reference
// A NamespacedReference to a named object.
type NamespacedReference = common.NamespacedReference
// 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.
type TypedReference struct {
// APIVersion of the referenced object.
APIVersion string `json:"apiVersion"`
// Kind of the referenced object.
Kind string `json:"kind"`
// Name of the referenced object.
Name string `json:"name"`
// UID of the referenced object.
// +optional
UID types.UID `json:"uid,omitempty"`
}
type TypedReference = common.TypedReference
// A Selector selects an object.
type Selector struct {
// MatchLabels ensures an object with matching labels is selected.
MatchLabels map[string]string `json:"matchLabels,omitempty"`
type Selector = common.Selector
// MatchControllerRef ensures an object with the same controller reference
// as the selecting object is selected.
MatchControllerRef *bool `json:"matchControllerRef,omitempty"`
}
// NamespacedSelector selects a namespaced object.
type NamespacedSelector = common.NamespacedSelector
// SetGroupVersionKind sets the Kind and APIVersion of a TypedReference.
func (obj *TypedReference) SetGroupVersionKind(gvk schema.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
}
// GroupVersionKind gets the GroupVersionKind of a TypedReference.
func (obj *TypedReference) GroupVersionKind() schema.GroupVersionKind {
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
}
// GetObjectKind get the ObjectKind of a TypedReference.
func (obj *TypedReference) GetObjectKind() schema.ObjectKind { return obj }
// ProviderConfigReference is a typed reference to a ProviderConfig
// object, with a known api group.
type ProviderConfigReference = common.ProviderConfigReference
// TODO(negz): Rename Resource* to Managed* to clarify that they enable the
// resource.Managed interface.
@ -142,14 +112,27 @@ type ResourceSpec struct {
// +kubebuilder:default={"name": "default"}
ProviderConfigReference *Reference `json:"providerConfigRef,omitempty"`
// ProviderReference specifies the provider that will be used to create,
// observe, update, and delete this managed resource.
// Deprecated: Please use ProviderConfigReference, i.e. `providerConfigRef`
ProviderReference *Reference `json:"providerRef,omitempty"`
// THIS IS A BETA FIELD. It is on by default but can be opted out
// through a Crossplane feature flag.
// ManagementPolicies specify the array of actions Crossplane is allowed to
// take on the managed and external resources.
// This field is planned to replace the DeletionPolicy field in a future
// release. Currently, both could be set independently and non-default
// values would be honored if the feature flag is enabled. If both are
// custom, the DeletionPolicy field will be ignored.
// See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223
// and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md
// +optional
// +kubebuilder:default={"*"}
ManagementPolicies ManagementPolicies `json:"managementPolicies,omitempty"`
// DeletionPolicy specifies what will happen to the underlying external
// when this managed resource is deleted - either "Delete" or "Orphan" the
// external resource.
// This field is planned to be deprecated in favor of the ManagementPolicies
// field in a future release. Currently, both could be set independently and
// non-default values would be honored if the feature flag is enabled.
// See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223
// +optional
// +kubebuilder:default=Delete
DeletionPolicy DeletionPolicy `json:"deletionPolicy,omitempty"`
@ -158,87 +141,58 @@ type ResourceSpec struct {
// ResourceStatus represents the observed state of a managed resource.
type ResourceStatus struct {
ConditionedStatus `json:",inline"`
ObservedStatus `json:",inline"`
}
// A CredentialsSource is a source from which provider credentials may be
// acquired.
type CredentialsSource string
type CredentialsSource = common.CredentialsSource
const (
// CredentialsSourceNone indicates that a provider does not require
// credentials.
CredentialsSourceNone CredentialsSource = "None"
CredentialsSourceNone = common.CredentialsSourceNone
// CredentialsSourceSecret indicates that a provider should acquire
// credentials from a secret.
CredentialsSourceSecret CredentialsSource = "Secret"
CredentialsSourceSecret = common.CredentialsSourceSecret
// CredentialsSourceInjectedIdentity indicates that a provider should use
// credentials via its (pod's) identity; i.e. via IRSA for AWS,
// Workload Identity for GCP, Pod Identity for Azure, or in-cluster
// authentication for the Kubernetes API.
CredentialsSourceInjectedIdentity CredentialsSource = "InjectedIdentity"
CredentialsSourceInjectedIdentity = common.CredentialsSourceInjectedIdentity
// CredentialsSourceEnvironment indicates that a provider should acquire
// credentials from an environment variable.
CredentialsSourceEnvironment CredentialsSource = "Environment"
CredentialsSourceEnvironment = common.CredentialsSourceEnvironment
// CredentialsSourceFilesystem indicates that a provider should acquire
// credentials from the filesystem.
CredentialsSourceFilesystem CredentialsSource = "Filesystem"
CredentialsSourceFilesystem = common.CredentialsSourceFilesystem
)
// CommonCredentialSelectors provides common selectors for extracting
// credentials.
type CommonCredentialSelectors struct {
// Fs is a reference to a filesystem location that contains credentials that
// must be used to connect to the provider.
// +optional
Fs *FsSelector `json:"fs,omitempty"`
// Env is a reference to an environment variable that contains credentials
// that must be used to connect to the provider.
// +optional
Env *EnvSelector `json:"env,omitempty"`
// A SecretRef is a reference to a secret key that contains the credentials
// that must be used to connect to the provider.
// +optional
SecretRef *SecretKeySelector `json:"secretRef,omitempty"`
}
type CommonCredentialSelectors = common.CommonCredentialSelectors
// EnvSelector selects an environment variable.
type EnvSelector struct {
// Name is the name of an environment variable.
Name string `json:"name"`
}
type EnvSelector = common.EnvSelector
// FsSelector selects a filesystem location.
type FsSelector struct {
// Path is a filesystem path.
Path string `json:"path"`
}
type FsSelector = common.FsSelector
// A ProviderConfigStatus defines the observed status of a ProviderConfig.
type ProviderConfigStatus struct {
ConditionedStatus `json:",inline"`
// Users of this provider configuration.
Users int64 `json:"users,omitempty"`
}
type ProviderConfigStatus = common.ProviderConfigStatus
// A ProviderConfigUsage is a record that a particular managed resource is using
// a particular provider configuration.
type ProviderConfigUsage struct {
// ProviderConfigReference to the provider config being used.
ProviderConfigReference Reference `json:"providerConfigRef"`
// ResourceReference to the managed resource using the provider config.
ResourceReference TypedReference `json:"resourceRef"`
}
type ProviderConfigUsage = common.ProviderConfigUsage
// A TargetSpec defines the common fields of objects used for exposing
// infrastructure to workloads that can be scheduled to.
//
// Deprecated.
type TargetSpec struct {
// WriteConnectionSecretToReference specifies the name of a Secret, in the
// same namespace as this target, to which any connection details for this
@ -256,6 +210,8 @@ type TargetSpec struct {
}
// A TargetStatus defines the observed status a target.
//
// Deprecated.
type TargetStatus struct {
ConditionedStatus `json:",inline"`
}

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
//go:build !ignore_autogenerated
/*
Copyright 2019 The Crossplane Authors.
Copyright 2025 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.
@ -24,167 +24,6 @@ import (
corev1 "k8s.io/api/core/v1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommonCredentialSelectors) DeepCopyInto(out *CommonCredentialSelectors) {
*out = *in
if in.Fs != nil {
in, out := &in.Fs, &out.Fs
*out = new(FsSelector)
**out = **in
}
if in.Env != nil {
in, out := &in.Env, &out.Env
*out = new(EnvSelector)
**out = **in
}
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(SecretKeySelector)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonCredentialSelectors.
func (in *CommonCredentialSelectors) DeepCopy() *CommonCredentialSelectors {
if in == nil {
return nil
}
out := new(CommonCredentialSelectors)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Condition) DeepCopyInto(out *Condition) {
*out = *in
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
func (in *Condition) DeepCopy() *Condition {
if in == nil {
return nil
}
out := new(Condition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConditionedStatus) DeepCopyInto(out *ConditionedStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionedStatus.
func (in *ConditionedStatus) DeepCopy() *ConditionedStatus {
if in == nil {
return nil
}
out := new(ConditionedStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnvSelector) DeepCopyInto(out *EnvSelector) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvSelector.
func (in *EnvSelector) DeepCopy() *EnvSelector {
if in == nil {
return nil
}
out := new(EnvSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FsSelector) DeepCopyInto(out *FsSelector) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FsSelector.
func (in *FsSelector) DeepCopy() *FsSelector {
if in == nil {
return nil
}
out := new(FsSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LocalSecretReference) DeepCopyInto(out *LocalSecretReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSecretReference.
func (in *LocalSecretReference) DeepCopy() *LocalSecretReference {
if in == nil {
return nil
}
out := new(LocalSecretReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) {
*out = *in
in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus.
func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus {
if in == nil {
return nil
}
out := new(ProviderConfigStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) {
*out = *in
out.ProviderConfigReference = in.ProviderConfigReference
out.ResourceReference = in.ResourceReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage.
func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage {
if in == nil {
return nil
}
out := new(ProviderConfigUsage)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Reference) DeepCopyInto(out *Reference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Reference.
func (in *Reference) DeepCopy() *Reference {
if in == nil {
return nil
}
out := new(Reference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) {
*out = *in
@ -196,12 +35,12 @@ func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) {
if in.ProviderConfigReference != nil {
in, out := &in.ProviderConfigReference, &out.ProviderConfigReference
*out = new(Reference)
**out = **in
(*in).DeepCopyInto(*out)
}
if in.ProviderReference != nil {
in, out := &in.ProviderReference, &out.ProviderReference
*out = new(Reference)
**out = **in
if in.ManagementPolicies != nil {
in, out := &in.ManagementPolicies, &out.ManagementPolicies
*out = make(ManagementPolicies, len(*in))
copy(*out, *in)
}
}
@ -219,6 +58,7 @@ func (in *ResourceSpec) DeepCopy() *ResourceSpec {
func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) {
*out = *in
in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
in.ObservedStatus.DeepCopyInto(&out.ObservedStatus)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus.
@ -231,64 +71,6 @@ func (in *ResourceStatus) DeepCopy() *ResourceStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
*out = *in
out.SecretReference = in.SecretReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
if in == nil {
return nil
}
out := new(SecretKeySelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretReference) DeepCopyInto(out *SecretReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference.
func (in *SecretReference) DeepCopy() *SecretReference {
if in == nil {
return nil
}
out := new(SecretReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Selector) DeepCopyInto(out *Selector) {
*out = *in
if in.MatchLabels != nil {
in, out := &in.MatchLabels, &out.MatchLabels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.MatchControllerRef != nil {
in, out := &in.MatchControllerRef, &out.MatchControllerRef
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector.
func (in *Selector) DeepCopy() *Selector {
if in == nil {
return nil
}
out := new(Selector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetSpec) DeepCopyInto(out *TargetSpec) {
*out = *in
@ -329,18 +111,3 @@ func (in *TargetStatus) DeepCopy() *TargetStatus {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TypedReference) DeepCopyInto(out *TypedReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypedReference.
func (in *TypedReference) DeepCopy() *TypedReference {
if in == nil {
return nil
}
out := new(TypedReference)
in.DeepCopyInto(out)
return out
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2020 The Crossplane Authors.
Copyright 2019 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.
@ -14,5 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package integration provides utilities for integration testing Crossplane.
package integration
// Package v2 contains core API types used by most Crossplane resources.
// +kubebuilder:object:generate=true
package v2

View File

@ -0,0 +1,51 @@
/*
Copyright 2019 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 v2
import (
"github.com/crossplane/crossplane-runtime/apis/common"
)
// A ManagedResourceSpec defines the desired state of a managed resource.
type ManagedResourceSpec struct {
// WriteConnectionSecretToReference specifies the namespace and name of a
// Secret to which any connection details for this managed resource should
// be written. Connection details frequently include the endpoint, username,
// and password required to connect to the managed resource.
// +optional
WriteConnectionSecretToReference *common.LocalSecretReference `json:"writeConnectionSecretToRef,omitempty"`
// ProviderConfigReference specifies how the provider that will be used to
// create, observe, update, and delete this managed resource should be
// configured.
// +kubebuilder:default={"kind": "ClusterProviderConfig", "name": "default"}
ProviderConfigReference *common.ProviderConfigReference `json:"providerConfigRef,omitempty"`
// THIS IS A BETA FIELD. It is on by default but can be opted out
// through a Crossplane feature flag.
// ManagementPolicies specify the array of actions Crossplane is allowed to
// take on the managed and external resources.
// See the design doc for more information: https://github.com/crossplane/crossplane/blob/499895a25d1a1a0ba1604944ef98ac7a1a71f197/design/design-doc-observe-only-resources.md?plain=1#L223
// and this one: https://github.com/crossplane/crossplane/blob/444267e84783136daa93568b364a5f01228cacbe/design/one-pager-ignore-changes.md
// +optional
// +kubebuilder:default={"*"}
ManagementPolicies common.ManagementPolicies `json:"managementPolicies,omitempty"`
}
// A TypedProviderConfigUsage is a record that a particular managed resource is using
// a particular provider configuration.
type TypedProviderConfigUsage = common.TypedProviderConfigUsage

View File

@ -0,0 +1,55 @@
//go:build !ignore_autogenerated
/*
Copyright 2025 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 controller-gen. DO NOT EDIT.
package v2
import (
"github.com/crossplane/crossplane-runtime/apis/common"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ManagedResourceSpec) DeepCopyInto(out *ManagedResourceSpec) {
*out = *in
if in.WriteConnectionSecretToReference != nil {
in, out := &in.WriteConnectionSecretToReference, &out.WriteConnectionSecretToReference
*out = new(common.LocalSecretReference)
**out = **in
}
if in.ProviderConfigReference != nil {
in, out := &in.ProviderConfigReference, &out.ProviderConfigReference
*out = new(common.ProviderConfigReference)
**out = **in
}
if in.ManagementPolicies != nil {
in, out := &in.ManagementPolicies, &out.ManagementPolicies
*out = make(common.ManagementPolicies, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedResourceSpec.
func (in *ManagedResourceSpec) DeepCopy() *ManagedResourceSpec {
if in == nil {
return nil
}
out := new(ManagedResourceSpec)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,468 @@
//go:build !ignore_autogenerated
/*
Copyright 2025 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 controller-gen. DO NOT EDIT.
package common
import ()
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommonCredentialSelectors) DeepCopyInto(out *CommonCredentialSelectors) {
*out = *in
if in.Fs != nil {
in, out := &in.Fs, &out.Fs
*out = new(FsSelector)
**out = **in
}
if in.Env != nil {
in, out := &in.Env, &out.Env
*out = new(EnvSelector)
**out = **in
}
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(SecretKeySelector)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonCredentialSelectors.
func (in *CommonCredentialSelectors) DeepCopy() *CommonCredentialSelectors {
if in == nil {
return nil
}
out := new(CommonCredentialSelectors)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Condition) DeepCopyInto(out *Condition) {
*out = *in
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
func (in *Condition) DeepCopy() *Condition {
if in == nil {
return nil
}
out := new(Condition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConditionedStatus) DeepCopyInto(out *ConditionedStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionedStatus.
func (in *ConditionedStatus) DeepCopy() *ConditionedStatus {
if in == nil {
return nil
}
out := new(ConditionedStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnvSelector) DeepCopyInto(out *EnvSelector) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvSelector.
func (in *EnvSelector) DeepCopy() *EnvSelector {
if in == nil {
return nil
}
out := new(EnvSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FsSelector) DeepCopyInto(out *FsSelector) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FsSelector.
func (in *FsSelector) DeepCopy() *FsSelector {
if in == nil {
return nil
}
out := new(FsSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LocalSecretKeySelector) DeepCopyInto(out *LocalSecretKeySelector) {
*out = *in
out.LocalSecretReference = in.LocalSecretReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSecretKeySelector.
func (in *LocalSecretKeySelector) DeepCopy() *LocalSecretKeySelector {
if in == nil {
return nil
}
out := new(LocalSecretKeySelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LocalSecretReference) DeepCopyInto(out *LocalSecretReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSecretReference.
func (in *LocalSecretReference) DeepCopy() *LocalSecretReference {
if in == nil {
return nil
}
out := new(LocalSecretReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ManagementPolicies) DeepCopyInto(out *ManagementPolicies) {
{
in := &in
*out = make(ManagementPolicies, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementPolicies.
func (in ManagementPolicies) DeepCopy() ManagementPolicies {
if in == nil {
return nil
}
out := new(ManagementPolicies)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MergeOptions) DeepCopyInto(out *MergeOptions) {
*out = *in
if in.KeepMapValues != nil {
in, out := &in.KeepMapValues, &out.KeepMapValues
*out = new(bool)
**out = **in
}
if in.AppendSlice != nil {
in, out := &in.AppendSlice, &out.AppendSlice
*out = new(bool)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MergeOptions.
func (in *MergeOptions) DeepCopy() *MergeOptions {
if in == nil {
return nil
}
out := new(MergeOptions)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NamespacedReference) DeepCopyInto(out *NamespacedReference) {
*out = *in
if in.Policy != nil {
in, out := &in.Policy, &out.Policy
*out = new(Policy)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespacedReference.
func (in *NamespacedReference) DeepCopy() *NamespacedReference {
if in == nil {
return nil
}
out := new(NamespacedReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NamespacedSelector) DeepCopyInto(out *NamespacedSelector) {
*out = *in
if in.MatchLabels != nil {
in, out := &in.MatchLabels, &out.MatchLabels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.MatchControllerRef != nil {
in, out := &in.MatchControllerRef, &out.MatchControllerRef
*out = new(bool)
**out = **in
}
if in.Policy != nil {
in, out := &in.Policy, &out.Policy
*out = new(Policy)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespacedSelector.
func (in *NamespacedSelector) DeepCopy() *NamespacedSelector {
if in == nil {
return nil
}
out := new(NamespacedSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObservedStatus) DeepCopyInto(out *ObservedStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObservedStatus.
func (in *ObservedStatus) DeepCopy() *ObservedStatus {
if in == nil {
return nil
}
out := new(ObservedStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Policy) DeepCopyInto(out *Policy) {
*out = *in
if in.Resolve != nil {
in, out := &in.Resolve, &out.Resolve
*out = new(ResolvePolicy)
**out = **in
}
if in.Resolution != nil {
in, out := &in.Resolution, &out.Resolution
*out = new(ResolutionPolicy)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy.
func (in *Policy) DeepCopy() *Policy {
if in == nil {
return nil
}
out := new(Policy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderConfigReference) DeepCopyInto(out *ProviderConfigReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigReference.
func (in *ProviderConfigReference) DeepCopy() *ProviderConfigReference {
if in == nil {
return nil
}
out := new(ProviderConfigReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) {
*out = *in
in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus.
func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus {
if in == nil {
return nil
}
out := new(ProviderConfigStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) {
*out = *in
in.ProviderConfigReference.DeepCopyInto(&out.ProviderConfigReference)
out.ResourceReference = in.ResourceReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage.
func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage {
if in == nil {
return nil
}
out := new(ProviderConfigUsage)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Reference) DeepCopyInto(out *Reference) {
*out = *in
if in.Policy != nil {
in, out := &in.Policy, &out.Policy
*out = new(Policy)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Reference.
func (in *Reference) DeepCopy() *Reference {
if in == nil {
return nil
}
out := new(Reference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) {
*out = *in
in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
out.ObservedStatus = in.ObservedStatus
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus.
func (in *ResourceStatus) DeepCopy() *ResourceStatus {
if in == nil {
return nil
}
out := new(ResourceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
*out = *in
out.SecretReference = in.SecretReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
if in == nil {
return nil
}
out := new(SecretKeySelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretReference) DeepCopyInto(out *SecretReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference.
func (in *SecretReference) DeepCopy() *SecretReference {
if in == nil {
return nil
}
out := new(SecretReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Selector) DeepCopyInto(out *Selector) {
*out = *in
if in.MatchLabels != nil {
in, out := &in.MatchLabels, &out.MatchLabels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.MatchControllerRef != nil {
in, out := &in.MatchControllerRef, &out.MatchControllerRef
*out = new(bool)
**out = **in
}
if in.Policy != nil {
in, out := &in.Policy, &out.Policy
*out = new(Policy)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector.
func (in *Selector) DeepCopy() *Selector {
if in == nil {
return nil
}
out := new(Selector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TypedProviderConfigUsage) DeepCopyInto(out *TypedProviderConfigUsage) {
*out = *in
out.ProviderConfigReference = in.ProviderConfigReference
out.ResourceReference = in.ResourceReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypedProviderConfigUsage.
func (in *TypedProviderConfigUsage) DeepCopy() *TypedProviderConfigUsage {
if in == nil {
return nil
}
out := new(TypedProviderConfigUsage)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TypedReference) DeepCopyInto(out *TypedReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypedReference.
func (in *TypedReference) DeepCopy() *TypedReference {
if in == nil {
return nil
}
out := new(TypedReference)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,607 @@
//
//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.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.5
// protoc (unknown)
// source: proto/v1alpha1/ess.proto
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
package v1alpha1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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)
)
// ConfigReference is used to refer a StoreConfig object.
type ConfigReference struct {
state protoimpl.MessageState `protogen:"open.v1"`
ApiVersion string `protobuf:"bytes,1,opt,name=api_version,json=apiVersion,proto3" json:"api_version,omitempty"`
Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"`
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ConfigReference) Reset() {
*x = ConfigReference{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ConfigReference) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigReference) ProtoMessage() {}
func (x *ConfigReference) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ConfigReference.ProtoReflect.Descriptor instead.
func (*ConfigReference) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{0}
}
func (x *ConfigReference) GetApiVersion() string {
if x != nil {
return x.ApiVersion
}
return ""
}
func (x *ConfigReference) GetKind() string {
if x != nil {
return x.Kind
}
return ""
}
func (x *ConfigReference) GetName() string {
if x != nil {
return x.Name
}
return ""
}
// Secret defines the structure of a secret.
type Secret struct {
state protoimpl.MessageState `protogen:"open.v1"`
ScopedName string `protobuf:"bytes,1,opt,name=scoped_name,json=scopedName,proto3" json:"scoped_name,omitempty"`
Metadata map[string]string `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
Data map[string][]byte `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Secret) Reset() {
*x = Secret{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Secret) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Secret) ProtoMessage() {}
func (x *Secret) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Secret.ProtoReflect.Descriptor instead.
func (*Secret) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{1}
}
func (x *Secret) GetScopedName() string {
if x != nil {
return x.ScopedName
}
return ""
}
func (x *Secret) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *Secret) GetData() map[string][]byte {
if x != nil {
return x.Data
}
return nil
}
// GetSecretRequest requests secret from the secret store.
type GetSecretRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Config *ConfigReference `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
Secret *Secret `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSecretRequest) Reset() {
*x = GetSecretRequest{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSecretRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSecretRequest) ProtoMessage() {}
func (x *GetSecretRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetSecretRequest.ProtoReflect.Descriptor instead.
func (*GetSecretRequest) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{2}
}
func (x *GetSecretRequest) GetConfig() *ConfigReference {
if x != nil {
return x.Config
}
return nil
}
func (x *GetSecretRequest) GetSecret() *Secret {
if x != nil {
return x.Secret
}
return nil
}
// GetSecretResponse returns the secret from the secret store.
type GetSecretResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Secret *Secret `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSecretResponse) Reset() {
*x = GetSecretResponse{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSecretResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSecretResponse) ProtoMessage() {}
func (x *GetSecretResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetSecretResponse.ProtoReflect.Descriptor instead.
func (*GetSecretResponse) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{3}
}
func (x *GetSecretResponse) GetSecret() *Secret {
if x != nil {
return x.Secret
}
return nil
}
// ApplySecretRequest applies the secret data update to the secret store.
type ApplySecretRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Config *ConfigReference `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
Secret *Secret `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ApplySecretRequest) Reset() {
*x = ApplySecretRequest{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ApplySecretRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ApplySecretRequest) ProtoMessage() {}
func (x *ApplySecretRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ApplySecretRequest.ProtoReflect.Descriptor instead.
func (*ApplySecretRequest) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{4}
}
func (x *ApplySecretRequest) GetConfig() *ConfigReference {
if x != nil {
return x.Config
}
return nil
}
func (x *ApplySecretRequest) GetSecret() *Secret {
if x != nil {
return x.Secret
}
return nil
}
// ApplySecretResponse returns if the secret is changed or not.
type ApplySecretResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Changed bool `protobuf:"varint,1,opt,name=changed,proto3" json:"changed,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ApplySecretResponse) Reset() {
*x = ApplySecretResponse{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ApplySecretResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ApplySecretResponse) ProtoMessage() {}
func (x *ApplySecretResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ApplySecretResponse.ProtoReflect.Descriptor instead.
func (*ApplySecretResponse) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{5}
}
func (x *ApplySecretResponse) GetChanged() bool {
if x != nil {
return x.Changed
}
return false
}
// DeleteKeysRequest deletes the secret from the secret store.
type DeleteKeysRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Config *ConfigReference `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
Secret *Secret `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteKeysRequest) Reset() {
*x = DeleteKeysRequest{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteKeysRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteKeysRequest) ProtoMessage() {}
func (x *DeleteKeysRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteKeysRequest.ProtoReflect.Descriptor instead.
func (*DeleteKeysRequest) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{6}
}
func (x *DeleteKeysRequest) GetConfig() *ConfigReference {
if x != nil {
return x.Config
}
return nil
}
func (x *DeleteKeysRequest) GetSecret() *Secret {
if x != nil {
return x.Secret
}
return nil
}
// DeleteKeysResponse is returned if the secret is deleted.
type DeleteKeysResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteKeysResponse) Reset() {
*x = DeleteKeysResponse{}
mi := &file_proto_v1alpha1_ess_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteKeysResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteKeysResponse) ProtoMessage() {}
func (x *DeleteKeysResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_v1alpha1_ess_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteKeysResponse.ProtoReflect.Descriptor instead.
func (*DeleteKeysResponse) Descriptor() ([]byte, []int) {
return file_proto_v1alpha1_ess_proto_rawDescGZIP(), []int{7}
}
var File_proto_v1alpha1_ess_proto protoreflect.FileDescriptor
var file_proto_v1alpha1_ess_proto_rawDesc = string([]byte{
0x0a, 0x18, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
0x2f, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x65, 0x73, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x22, 0x5a,
0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63,
0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x9f, 0x02, 0x0a, 0x06, 0x53,
0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x5f,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x63, 0x6f, 0x70,
0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65,
0x63, 0x72, 0x65, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x38, 0x0a, 0x04,
0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x65, 0x73, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 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, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 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, 0x83, 0x01, 0x0a,
0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x3b, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x23, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31,
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x66,
0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32,
0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70,
0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72,
0x65, 0x74, 0x22, 0x47, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x85, 0x01, 0x0a, 0x12,
0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x23, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65,
0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x32, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c,
0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x06, 0x73, 0x65, 0x63,
0x72, 0x65, 0x74, 0x22, 0x2f, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68,
0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x64, 0x22, 0x84, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b,
0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x65, 0x73, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52,
0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x32, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x14, 0x0a, 0x12, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x32, 0xbf, 0x02, 0x0a, 0x20, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x65,
0x63, 0x72, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5a, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x12, 0x24, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x65, 0x73, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x47,
0x65, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x60, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65,
0x74, 0x12, 0x26, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31,
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x65, 0x73, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x41,
0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65,
0x79, 0x73, 0x12, 0x25, 0x2e, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65,
0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x65, 0x73, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x42, 0x3e, 0x5a, 0x3c, 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, 0x2d, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f,
0x61, 0x70, 0x69, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70,
0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
})
var (
file_proto_v1alpha1_ess_proto_rawDescOnce sync.Once
file_proto_v1alpha1_ess_proto_rawDescData []byte
)
func file_proto_v1alpha1_ess_proto_rawDescGZIP() []byte {
file_proto_v1alpha1_ess_proto_rawDescOnce.Do(func() {
file_proto_v1alpha1_ess_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_v1alpha1_ess_proto_rawDesc), len(file_proto_v1alpha1_ess_proto_rawDesc)))
})
return file_proto_v1alpha1_ess_proto_rawDescData
}
var file_proto_v1alpha1_ess_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_proto_v1alpha1_ess_proto_goTypes = []any{
(*ConfigReference)(nil), // 0: ess.proto.v1alpha1.ConfigReference
(*Secret)(nil), // 1: ess.proto.v1alpha1.Secret
(*GetSecretRequest)(nil), // 2: ess.proto.v1alpha1.GetSecretRequest
(*GetSecretResponse)(nil), // 3: ess.proto.v1alpha1.GetSecretResponse
(*ApplySecretRequest)(nil), // 4: ess.proto.v1alpha1.ApplySecretRequest
(*ApplySecretResponse)(nil), // 5: ess.proto.v1alpha1.ApplySecretResponse
(*DeleteKeysRequest)(nil), // 6: ess.proto.v1alpha1.DeleteKeysRequest
(*DeleteKeysResponse)(nil), // 7: ess.proto.v1alpha1.DeleteKeysResponse
nil, // 8: ess.proto.v1alpha1.Secret.MetadataEntry
nil, // 9: ess.proto.v1alpha1.Secret.DataEntry
}
var file_proto_v1alpha1_ess_proto_depIdxs = []int32{
8, // 0: ess.proto.v1alpha1.Secret.metadata:type_name -> ess.proto.v1alpha1.Secret.MetadataEntry
9, // 1: ess.proto.v1alpha1.Secret.data:type_name -> ess.proto.v1alpha1.Secret.DataEntry
0, // 2: ess.proto.v1alpha1.GetSecretRequest.config:type_name -> ess.proto.v1alpha1.ConfigReference
1, // 3: ess.proto.v1alpha1.GetSecretRequest.secret:type_name -> ess.proto.v1alpha1.Secret
1, // 4: ess.proto.v1alpha1.GetSecretResponse.secret:type_name -> ess.proto.v1alpha1.Secret
0, // 5: ess.proto.v1alpha1.ApplySecretRequest.config:type_name -> ess.proto.v1alpha1.ConfigReference
1, // 6: ess.proto.v1alpha1.ApplySecretRequest.secret:type_name -> ess.proto.v1alpha1.Secret
0, // 7: ess.proto.v1alpha1.DeleteKeysRequest.config:type_name -> ess.proto.v1alpha1.ConfigReference
1, // 8: ess.proto.v1alpha1.DeleteKeysRequest.secret:type_name -> ess.proto.v1alpha1.Secret
2, // 9: ess.proto.v1alpha1.ExternalSecretStorePluginService.GetSecret:input_type -> ess.proto.v1alpha1.GetSecretRequest
4, // 10: ess.proto.v1alpha1.ExternalSecretStorePluginService.ApplySecret:input_type -> ess.proto.v1alpha1.ApplySecretRequest
6, // 11: ess.proto.v1alpha1.ExternalSecretStorePluginService.DeleteKeys:input_type -> ess.proto.v1alpha1.DeleteKeysRequest
3, // 12: ess.proto.v1alpha1.ExternalSecretStorePluginService.GetSecret:output_type -> ess.proto.v1alpha1.GetSecretResponse
5, // 13: ess.proto.v1alpha1.ExternalSecretStorePluginService.ApplySecret:output_type -> ess.proto.v1alpha1.ApplySecretResponse
7, // 14: ess.proto.v1alpha1.ExternalSecretStorePluginService.DeleteKeys:output_type -> ess.proto.v1alpha1.DeleteKeysResponse
12, // [12:15] is the sub-list for method output_type
9, // [9:12] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name
9, // [9:9] is the sub-list for extension extendee
0, // [0:9] is the sub-list for field type_name
}
func init() { file_proto_v1alpha1_ess_proto_init() }
func file_proto_v1alpha1_ess_proto_init() {
if File_proto_v1alpha1_ess_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_v1alpha1_ess_proto_rawDesc), len(file_proto_v1alpha1_ess_proto_rawDesc)),
NumEnums: 0,
NumMessages: 10,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_v1alpha1_ess_proto_goTypes,
DependencyIndexes: file_proto_v1alpha1_ess_proto_depIdxs,
MessageInfos: file_proto_v1alpha1_ess_proto_msgTypes,
}.Build()
File_proto_v1alpha1_ess_proto = out.File
file_proto_v1alpha1_ess_proto_goTypes = nil
file_proto_v1alpha1_ess_proto_depIdxs = nil
}

View File

@ -0,0 +1,71 @@
/*
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.
*/
syntax = "proto3";
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
package ess.proto.v1alpha1;
option go_package = "github.com/crossplane/crossplane-runtime/apis/proto/v1alpha1";
// ExternalSecretStorePluginService defines the APIs for an External Secret Store plugin.
service ExternalSecretStorePluginService {
rpc GetSecret(GetSecretRequest) returns (GetSecretResponse) {}
rpc ApplySecret(ApplySecretRequest) returns (ApplySecretResponse) {}
rpc DeleteKeys(DeleteKeysRequest) returns (DeleteKeysResponse) {}
}
// ConfigReference is used to refer a StoreConfig object.
message ConfigReference {
string api_version = 1;
string kind = 2;
string name = 3;
}
// Secret defines the structure of a secret.
message Secret {
string scoped_name = 1;
map<string, string> metadata = 2;
map<string, bytes> data = 3;
}
// GetSecretRequest requests secret from the secret store.
message GetSecretRequest {
ConfigReference config = 1;
Secret secret = 2;
}
// GetSecretResponse returns the secret from the secret store.
message GetSecretResponse {
Secret secret = 1;
}
// ApplySecretRequest applies the secret data update to the secret store.
message ApplySecretRequest {
ConfigReference config = 1;
Secret secret = 2;
}
// ApplySecretResponse returns if the secret is changed or not.
message ApplySecretResponse {
bool changed = 1;
}
// DeleteKeysRequest deletes the secret from the secret store.
message DeleteKeysRequest {
ConfigReference config = 1;
Secret secret = 2;
}
// DeleteKeysResponse is returned if the secret is deleted.
message DeleteKeysResponse {}

View File

@ -0,0 +1,198 @@
//
//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.
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc (unknown)
// source: proto/v1alpha1/ess.proto
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
package v1alpha1
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 (
ExternalSecretStorePluginService_GetSecret_FullMethodName = "/ess.proto.v1alpha1.ExternalSecretStorePluginService/GetSecret"
ExternalSecretStorePluginService_ApplySecret_FullMethodName = "/ess.proto.v1alpha1.ExternalSecretStorePluginService/ApplySecret"
ExternalSecretStorePluginService_DeleteKeys_FullMethodName = "/ess.proto.v1alpha1.ExternalSecretStorePluginService/DeleteKeys"
)
// ExternalSecretStorePluginServiceClient is the client API for ExternalSecretStorePluginService 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 ExternalSecretStorePluginServiceClient interface {
GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error)
ApplySecret(ctx context.Context, in *ApplySecretRequest, opts ...grpc.CallOption) (*ApplySecretResponse, error)
DeleteKeys(ctx context.Context, in *DeleteKeysRequest, opts ...grpc.CallOption) (*DeleteKeysResponse, error)
}
type externalSecretStorePluginServiceClient struct {
cc grpc.ClientConnInterface
}
func NewExternalSecretStorePluginServiceClient(cc grpc.ClientConnInterface) ExternalSecretStorePluginServiceClient {
return &externalSecretStorePluginServiceClient{cc}
}
func (c *externalSecretStorePluginServiceClient) GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) {
out := new(GetSecretResponse)
err := c.cc.Invoke(ctx, ExternalSecretStorePluginService_GetSecret_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *externalSecretStorePluginServiceClient) ApplySecret(ctx context.Context, in *ApplySecretRequest, opts ...grpc.CallOption) (*ApplySecretResponse, error) {
out := new(ApplySecretResponse)
err := c.cc.Invoke(ctx, ExternalSecretStorePluginService_ApplySecret_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *externalSecretStorePluginServiceClient) DeleteKeys(ctx context.Context, in *DeleteKeysRequest, opts ...grpc.CallOption) (*DeleteKeysResponse, error) {
out := new(DeleteKeysResponse)
err := c.cc.Invoke(ctx, ExternalSecretStorePluginService_DeleteKeys_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ExternalSecretStorePluginServiceServer is the server API for ExternalSecretStorePluginService service.
// All implementations must embed UnimplementedExternalSecretStorePluginServiceServer
// for forward compatibility
type ExternalSecretStorePluginServiceServer interface {
GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error)
ApplySecret(context.Context, *ApplySecretRequest) (*ApplySecretResponse, error)
DeleteKeys(context.Context, *DeleteKeysRequest) (*DeleteKeysResponse, error)
mustEmbedUnimplementedExternalSecretStorePluginServiceServer()
}
// UnimplementedExternalSecretStorePluginServiceServer must be embedded to have forward compatible implementations.
type UnimplementedExternalSecretStorePluginServiceServer struct {
}
func (UnimplementedExternalSecretStorePluginServiceServer) GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSecret not implemented")
}
func (UnimplementedExternalSecretStorePluginServiceServer) ApplySecret(context.Context, *ApplySecretRequest) (*ApplySecretResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ApplySecret not implemented")
}
func (UnimplementedExternalSecretStorePluginServiceServer) DeleteKeys(context.Context, *DeleteKeysRequest) (*DeleteKeysResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteKeys not implemented")
}
func (UnimplementedExternalSecretStorePluginServiceServer) mustEmbedUnimplementedExternalSecretStorePluginServiceServer() {
}
// UnsafeExternalSecretStorePluginServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ExternalSecretStorePluginServiceServer will
// result in compilation errors.
type UnsafeExternalSecretStorePluginServiceServer interface {
mustEmbedUnimplementedExternalSecretStorePluginServiceServer()
}
func RegisterExternalSecretStorePluginServiceServer(s grpc.ServiceRegistrar, srv ExternalSecretStorePluginServiceServer) {
s.RegisterService(&ExternalSecretStorePluginService_ServiceDesc, srv)
}
func _ExternalSecretStorePluginService_GetSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetSecretRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ExternalSecretStorePluginServiceServer).GetSecret(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ExternalSecretStorePluginService_GetSecret_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ExternalSecretStorePluginServiceServer).GetSecret(ctx, req.(*GetSecretRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ExternalSecretStorePluginService_ApplySecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ApplySecretRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ExternalSecretStorePluginServiceServer).ApplySecret(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ExternalSecretStorePluginService_ApplySecret_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ExternalSecretStorePluginServiceServer).ApplySecret(ctx, req.(*ApplySecretRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ExternalSecretStorePluginService_DeleteKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteKeysRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ExternalSecretStorePluginServiceServer).DeleteKeys(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ExternalSecretStorePluginService_DeleteKeys_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ExternalSecretStorePluginServiceServer).DeleteKeys(ctx, req.(*DeleteKeysRequest))
}
return interceptor(ctx, in, info, handler)
}
// ExternalSecretStorePluginService_ServiceDesc is the grpc.ServiceDesc for ExternalSecretStorePluginService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ExternalSecretStorePluginService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "ess.proto.v1alpha1.ExternalSecretStorePluginService",
HandlerType: (*ExternalSecretStorePluginServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetSecret",
Handler: _ExternalSecretStorePluginService_GetSecret_Handler,
},
{
MethodName: "ApplySecret",
Handler: _ExternalSecretStorePluginService_ApplySecret_Handler,
},
{
MethodName: "DeleteKeys",
Handler: _ExternalSecretStorePluginService_DeleteKeys_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "proto/v1alpha1/ess.proto",
}

1
build

@ -1 +0,0 @@
Subproject commit 066208d58f0529e36048c76a4ac46c3afd2b06d1

93
go.mod
View File

@ -1,19 +1,84 @@
module github.com/crossplane/crossplane-runtime
go 1.13
go 1.24.0
require (
github.com/go-logr/logr v0.3.0
github.com/google/go-cmp v0.5.2
github.com/hashicorp/go-getter v1.4.0
github.com/pkg/errors v0.9.1
github.com/spf13/afero v1.2.2
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
k8s.io/api v0.20.1
k8s.io/apiextensions-apiserver v0.20.1
k8s.io/apimachinery v0.20.1
k8s.io/client-go v0.20.1
sigs.k8s.io/controller-runtime v0.8.0
sigs.k8s.io/controller-tools v0.2.4
sigs.k8s.io/yaml v1.2.0
dario.cat/mergo v1.0.1
github.com/evanphx/json-patch v5.9.11+incompatible
github.com/go-logr/logr v1.4.2
github.com/google/go-cmp v0.7.0
github.com/prometheus/client_golang v1.22.0
github.com/spf13/afero v1.11.0
golang.org/x/time v0.9.0
google.golang.org/grpc v1.68.1
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
google.golang.org/protobuf v1.36.5
k8s.io/api v0.33.0
k8s.io/apiextensions-apiserver v0.33.0
k8s.io/apimachinery v0.33.0
k8s.io/client-go v0.33.0
k8s.io/component-base v0.33.0
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
sigs.k8s.io/controller-runtime v0.19.0
sigs.k8s.io/controller-tools v0.18.0
sigs.k8s.io/yaml v1.4.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gobuffalo/flect v1.0.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/oauth2 v0.27.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/term v0.31.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/tools v0.32.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // 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
k8s.io/code-generator v0.33.0 // indirect
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
)

1156
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Crossplane Authors.
Copyright 2025 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.

View File

@ -1,3 +1,3 @@
`{{violation.rule}}`: {{violation.message}}
Refer to Crossplane's [coding style documentation](https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md#coding-style-and-linting) for more information.
Refer to Crossplane's [coding style documentation](https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md#coding-style-and-linting) for more information.

View File

@ -0,0 +1,70 @@
/*
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 certificates loads TLS certificates from a given folder.
package certificates
import (
"crypto/tls"
"crypto/x509"
"os"
"path/filepath"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
const (
errLoadCert = "cannot load certificate"
errLoadCA = "cannot load CA certificate"
errInvalidCA = "invalid CA certificate"
)
// LoadMTLSConfig loads TLS certificates in the given folder using well-defined filenames for certificates in a Kubernetes environment.
func LoadMTLSConfig(caPath, certPath, keyPath string, isServer bool) (*tls.Config, error) {
tlsCertFilePath := filepath.Clean(certPath)
tlsKeyFilePath := filepath.Clean(keyPath)
certificate, err := tls.LoadX509KeyPair(tlsCertFilePath, tlsKeyFilePath)
if err != nil {
return nil, errors.Wrap(err, errLoadCert)
}
caCertFilePath := filepath.Clean(caPath)
ca, err := os.ReadFile(caCertFilePath)
if err != nil {
return nil, errors.Wrap(err, errLoadCA)
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(ca) {
return nil, errors.New(errInvalidCA)
}
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{certificate},
}
if isServer {
tlsConfig.ClientCAs = pool
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
} else {
tlsConfig.RootCAs = pool
}
return tlsConfig, nil
}

View File

@ -0,0 +1,112 @@
package certificates
import (
"crypto/tls"
"path/filepath"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/crossplane/crossplane-runtime/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
var (
errNoSuchFile = errors.New("open invalid/path/tls.crt: no such file or directory")
errNoCAFile = errors.New("open test-data/no-ca/ca.crt: no such file or directory")
)
const (
caCertFileName = "ca.crt"
tlsCertFileName = "tls.crt"
tlsKeyFileName = "tls.key"
)
func TestLoad(t *testing.T) {
type args struct {
certsFolderPath string
requireClientValidation bool
}
type want struct {
err error
out *tls.Config
}
cases := map[string]struct {
reason string
args
want
}{
"LoadCertError": {
reason: "Should return a proper error if certificates do not exist.",
args: args{
certsFolderPath: "invalid/path",
},
want: want{
err: errors.Wrap(errNoSuchFile, errLoadCert),
out: nil,
},
},
"LoadCAError": {
reason: "Should return a proper error if CA certificate does not exist.",
args: args{
certsFolderPath: "test-data/no-ca",
},
want: want{
err: errors.Wrap(errNoCAFile, errLoadCA),
out: nil,
},
},
"InvalidCAError": {
reason: "Should return a proper error if CA certificate is not valid.",
args: args{
certsFolderPath: "test-data/invalid-certs/",
},
want: want{
err: errors.New(errInvalidCA),
out: nil,
},
},
"NoError": {
reason: "Should not return an error after loading certificates.",
args: args{
certsFolderPath: "test-data/certs/",
},
want: want{
err: nil,
out: &tls.Config{},
},
},
"NoErrorWithClientValidation": {
reason: "Should not return an error after loading certificates.",
args: args{
certsFolderPath: "test-data/certs/",
requireClientValidation: true,
},
want: want{
err: nil,
out: &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
},
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
certsFolderPath := tc.certsFolderPath
requireClient := tc.requireClientValidation
cfg, err := LoadMTLSConfig(filepath.Join(certsFolderPath, caCertFileName), filepath.Join(certsFolderPath, tlsCertFileName), filepath.Join(certsFolderPath, tlsKeyFileName), requireClient)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nLoad(...): -want error, +got error:\n%s", tc.reason, diff)
}
if requireClient {
if diff := cmp.Diff(tc.out.ClientAuth, cfg.ClientAuth); diff != "" {
t.Errorf("\n%s\nLoad(...): -want, +got:\n%s", tc.reason, diff)
}
}
})
}
}

View File

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBejCCASGgAwIBAgIIOGozHYTTZu4wCgYIKoZIzj0EAwIwETEPMA0GA1UEAxMG
Um9vdENBMCAXDTE5MTIyMzA4NTYzN1oYDzIxMTkxMTI5MDkwMTM3WjARMQ8wDQYD
VQQDEwZSb290Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQmKXRMMLbjn8ur
DaO/rNa8VXq32FHt7wr8+xXf0OhaCimQHxWmCHXmierP+UWs4TwZ5/NTyHZ8OOCj
sSEGgA1ao2EwXzAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNQ5LeIUMgDmha6m
HlW5Yte2trnyMAoGCCqGSM49BAMCA0cAMEQCIACPtB0wO8CGBjdANqnHOnREgEqu
KieHeY3sYL2H+7YfAiAmfLtMe3hPdI3+sDPVZTPDe8HYFher8yWb/DCBZCT1Ww==
-----END CERTIFICATE-----

View File

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBxDCCAWmgAwIBAgIUVkhaF0okPcEJaKYKJRyTHU+aQMwwCgYIKoZIzj0EAwIw
ETEPMA0GA1UEAxMGUm9vdENBMCAXDTE5MTIyMzA4NTkwMFoYDzIxMTkxMTI5MDg1
OTAwWjARMQ8wDQYDVQQDEwZjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AASyDjp+6zyn0W2MWtX07u3iudcahyLtTD51DzTIdplcT/bezWBWxLnP0JzzGORS
f/Uf59PjMCbE66fFSNCQpcdlo4GcMIGZMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
rRNJVmij3xwiQyNfzKuhcCKnAtAwHwYDVR0jBBgwFoAU1Dkt4hQyAOaFrqYeVbli
17a2ufIwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMAoGCCqGSM49BAMCA0kA
MEYCIQCpZppRb5t2kjyILMnLhJ/cHKsvXpAWcO8FrDx/VBoP1wIhALtw1B73X2bj
EPps3Or2UzJNxNroBNRgqIo7XkaKQRe8
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDcpnLnAoOvR+q7rEKEY4zEWTicMkPaHJ1iC8lHEy9v8oAoGCCqGSM49
AwEHoUQDQgAEsg46fus8p9FtjFrV9O7t4rnXGoci7Uw+dQ80yHaZXE/23s1gVsS5
z9Cc8xjkUn/1H+fT4zAmxOunxUjQkKXHZQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,8 @@
MIIBejCCASGgAwIBAgIIOGozHYTTZu4wCgYIKoZIzj0EAwIwETEPMA0GA1UEAxMG
Um9vdENBMCAXDTE5MTIyMzA4NTYzN1oYDzIxMTkxMTI5MDkwMTM3WjARMQ8wDQYD
VQQDEwZSb290Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQmKXRMMLbjn8ur
DaO/rNa8VXq32FHt7wr8+xXf0OhaCimQHxWmCHXmierP+UWs4TwZ5/NTyHZ8OOCj
sSEGgA1ao2EwXzAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNQ5LeIUMgDmha6m
HlW5Yte2trnyMAoGCCqGSM49BAMCA0cAMEQCIACPtB0wO8CGBjdANqnHOnREgEqu
KieHeY3sYL2H+7YfAiAmfLtMe3hPdI3+sDPVZTPDe8HYFher8yWb/DCBZCT1Ww==

View File

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBxDCCAWmgAwIBAgIUVkhaF0okPcEJaKYKJRyTHU+aQMwwCgYIKoZIzj0EAwIw
ETEPMA0GA1UEAxMGUm9vdENBMCAXDTE5MTIyMzA4NTkwMFoYDzIxMTkxMTI5MDg1
OTAwWjARMQ8wDQYDVQQDEwZjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AASyDjp+6zyn0W2MWtX07u3iudcahyLtTD51DzTIdplcT/bezWBWxLnP0JzzGORS
f/Uf59PjMCbE66fFSNCQpcdlo4GcMIGZMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
rRNJVmij3xwiQyNfzKuhcCKnAtAwHwYDVR0jBBgwFoAU1Dkt4hQyAOaFrqYeVbli
17a2ufIwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMAoGCCqGSM49BAMCA0kA
MEYCIQCpZppRb5t2kjyILMnLhJ/cHKsvXpAWcO8FrDx/VBoP1wIhALtw1B73X2bj
EPps3Or2UzJNxNroBNRgqIo7XkaKQRe8
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDcpnLnAoOvR+q7rEKEY4zEWTicMkPaHJ1iC8lHEy9v8oAoGCCqGSM49
AwEHoUQDQgAEsg46fus8p9FtjFrV9O7t4rnXGoci7Uw+dQ80yHaZXE/23s1gVsS5
z9Cc8xjkUn/1H+fT4zAmxOunxUjQkKXHZQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBxDCCAWmgAwIBAgIUVkhaF0okPcEJaKYKJRyTHU+aQMwwCgYIKoZIzj0EAwIw
ETEPMA0GA1UEAxMGUm9vdENBMCAXDTE5MTIyMzA4NTkwMFoYDzIxMTkxMTI5MDg1
OTAwWjARMQ8wDQYDVQQDEwZjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AASyDjp+6zyn0W2MWtX07u3iudcahyLtTD51DzTIdplcT/bezWBWxLnP0JzzGORS
f/Uf59PjMCbE66fFSNCQpcdlo4GcMIGZMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
rRNJVmij3xwiQyNfzKuhcCKnAtAwHwYDVR0jBBgwFoAU1Dkt4hQyAOaFrqYeVbli
17a2ufIwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMAoGCCqGSM49BAMCA0kA
MEYCIQCpZppRb5t2kjyILMnLhJ/cHKsvXpAWcO8FrDx/VBoP1wIhALtw1B73X2bj
EPps3Or2UzJNxNroBNRgqIo7XkaKQRe8
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDcpnLnAoOvR+q7rEKEY4zEWTicMkPaHJ1iC8lHEy9v8oAoGCCqGSM49
AwEHoUQDQgAEsg46fus8p9FtjFrV9O7t4rnXGoci7Uw+dQ80yHaZXE/23s1gVsS5
z9Cc8xjkUn/1H+fT4zAmxOunxUjQkKXHZQ==
-----END EC PRIVATE KEY-----

73
pkg/conditions/manager.go Normal file
View File

@ -0,0 +1,73 @@
/*
Copyright 2025 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 conditions enables consistent interactions with an object's status conditions.
package conditions
import (
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/resource"
)
// ObjectWithConditions is the interface definition that allows.
type ObjectWithConditions interface {
resource.Object
resource.Conditioned
}
// Manager is an interface for a stateless factory-like object that produces ConditionSet objects.
type Manager interface {
// For returns an implementation of a ConditionSet to operate on a specific ObjectWithConditions.
For(o ObjectWithConditions) ConditionSet
}
// ConditionSet holds operations for interacting with an object's conditions.
type ConditionSet interface {
// MarkConditions adds or updates the conditions onto the managed resource object. Unlike a "Set" method, this also
// can add contextual updates to the condition such as propagating the correct observedGeneration to the conditions
// being changed.
MarkConditions(condition ...xpv1.Condition)
}
// ObservedGenerationPropagationManager is the top level factor for producing a ConditionSet
// on behalf of a ObjectWithConditions resource, the ConditionSet is only currently concerned with
// propagating observedGeneration to conditions that are being updated.
// observedGenerationPropagationManager implements Manager.
type ObservedGenerationPropagationManager struct{}
// For implements Manager.For.
func (m ObservedGenerationPropagationManager) For(o ObjectWithConditions) ConditionSet {
return &observedGenerationPropagationConditionSet{o: o}
}
// observedGenerationPropagationConditionSet propagates the meta.generation of the given object
// to the observedGeneration of any condition being set via the `MarkConditions` method.
type observedGenerationPropagationConditionSet struct {
o ObjectWithConditions
}
// MarkConditions implements ConditionSet.MarkConditions.
func (c *observedGenerationPropagationConditionSet) MarkConditions(condition ...xpv1.Condition) {
if c == nil || c.o == nil {
return
}
// Foreach condition we have been sent to mark, update the observed generation.
for i := range condition {
condition[i].ObservedGeneration = c.o.GetGeneration()
}
c.o.SetConditions(condition...)
}

View File

@ -0,0 +1,135 @@
/*
Copyright 2025 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 conditions
import (
"reflect"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
// Check that conditionsImpl implements ConditionManager.
var _ Manager = (*ObservedGenerationPropagationManager)(nil)
// Check that conditionSet implements ConditionSet.
var _ ConditionSet = (*observedGenerationPropagationConditionSet)(nil)
func TestOGConditionSetMark(t *testing.T) {
manager := new(ObservedGenerationPropagationManager)
tests := map[string]struct {
reason string
start []xpv1.Condition
mark []xpv1.Condition
want []xpv1.Condition
}{
"ProvideNoConditions": {
reason: "If updating a resource without conditions with no new conditions, conditions should remain empty.",
start: nil,
mark: nil,
want: nil,
},
"EmptyAppendCondition": {
reason: "If starting with a resource without conditions, and we mark a condition, it should propagate to conditions with the correct generation.",
start: nil,
mark: []xpv1.Condition{xpv1.ReconcileSuccess()},
want: []xpv1.Condition{xpv1.ReconcileSuccess().WithObservedGeneration(42)},
},
"ExistingMarkNothing": {
reason: "If the resource has a condition and we update nothing, nothing should change.",
start: []xpv1.Condition{xpv1.Available().WithObservedGeneration(1)},
mark: nil,
want: []xpv1.Condition{xpv1.Available().WithObservedGeneration(1)},
},
"ExistingUpdated": {
reason: "If a resource starts with a condition, and we update it, we should see the observedGeneration be updated",
start: []xpv1.Condition{xpv1.ReconcileSuccess().WithObservedGeneration(1)},
mark: []xpv1.Condition{xpv1.ReconcileSuccess()},
want: []xpv1.Condition{xpv1.ReconcileSuccess().WithObservedGeneration(42)},
},
"ExistingAppended": {
reason: "If a resource has an existing condition and we make another condition, the new condition should merge into the conditions list.",
start: []xpv1.Condition{xpv1.Available().WithObservedGeneration(1)},
mark: []xpv1.Condition{xpv1.ReconcileSuccess()},
want: []xpv1.Condition{xpv1.Available().WithObservedGeneration(1), xpv1.ReconcileSuccess().WithObservedGeneration(42)},
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
ut := newManaged(42, tt.start...)
c := manager.For(ut)
c.MarkConditions(tt.mark...)
if diff := cmp.Diff(tt.want, ut.Conditions, test.EquateConditions(), cmpopts.EquateApproxTime(1*time.Second)); diff != "" {
t.Errorf("\nReason: %s\n-want, +got:\n%s", tt.reason, diff)
}
})
}
t.Run("ManageNilObject", func(t *testing.T) {
c := manager.For(nil)
if c == nil {
t.Errorf("manager.For(nil) = %v, want non-nil", c)
}
// Test that Marking on a Manager that has a nil object does not end up panicking.
c.MarkConditions(xpv1.ReconcileSuccess())
// Success!
})
}
func TestOGManagerFor(t *testing.T) {
tests := map[string]struct {
reason string
o ObjectWithConditions
want ConditionSet
}{
"NilObject": {
reason: "Even if an object is nil, the manager should return a non-nil ConditionSet",
want: &observedGenerationPropagationConditionSet{},
},
"Object": {
reason: "Object propagates into manager.",
o: &fake.Managed{},
want: &observedGenerationPropagationConditionSet{
o: &fake.Managed{},
},
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
m := &ObservedGenerationPropagationManager{}
if got := m.For(tt.o); !reflect.DeepEqual(got, tt.want) {
t.Errorf("\nReason: %s\nFor() = %v, want %v", tt.reason, got, tt.want)
}
})
}
}
func newManaged(generation int64, conditions ...xpv1.Condition) *fake.Managed {
mg := &fake.Managed{}
mg.Generation = generation
mg.SetConditions(conditions...)
return mg
}

View File

@ -1,208 +0,0 @@
/*
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 controller provides utilties for working with controllers.
package controller
import (
"context"
"sync"
"github.com/pkg/errors"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/source"
)
// Error strings
const (
errCreateCache = "cannot create new cache"
errCreateController = "cannot create new controller"
errCrashCache = "cache error"
errCrashController = "controller error"
errWatch = "cannot setup watch"
)
// A NewCacheFn creates a new controller-runtime cache.
type NewCacheFn func(cfg *rest.Config, o cache.Options) (cache.Cache, error)
// A NewControllerFn creates a new controller-runtime controller.
type NewControllerFn func(name string, m manager.Manager, o controller.Options) (controller.Controller, error)
// The default new cache and new controller functions.
var (
DefaultNewCacheFn NewCacheFn = cache.New
DefaultNewControllerFn NewControllerFn = controller.NewUnmanaged
)
// An Engine manages the lifecycles of controller-runtime controllers (and their
// caches). The lifecycles of the controllers are not coupled to lifecycle of
// the engine, nor to the lifecycle of the controller manager it uses.
type Engine struct {
mgr manager.Manager
started map[string]context.CancelFunc
errors map[string]error
mx sync.RWMutex
newCache NewCacheFn
newCtrl NewControllerFn
}
// An EngineOption configures an Engine.
type EngineOption func(*Engine)
// WithNewCacheFn may be used to configure a different cache implementation.
// DefaultNewCacheFn is used by default.
func WithNewCacheFn(fn NewCacheFn) EngineOption {
return func(e *Engine) {
e.newCache = fn
}
}
// WithNewControllerFn may be used to configure a different controller
// implementation. DefaultNewControllerFn is used by default.
func WithNewControllerFn(fn NewControllerFn) EngineOption {
return func(e *Engine) {
e.newCtrl = fn
}
}
// NewEngine produces a new Engine.
func NewEngine(mgr manager.Manager, o ...EngineOption) *Engine {
e := &Engine{
mgr: mgr,
started: make(map[string]context.CancelFunc),
errors: make(map[string]error),
newCache: DefaultNewCacheFn,
newCtrl: DefaultNewControllerFn,
}
for _, eo := range o {
eo(e)
}
return e
}
// IsRunning indicates whether the named controller is running - i.e. whether it
// has been started and does not appear to have crashed.
func (e *Engine) IsRunning(name string) bool {
e.mx.RLock()
defer e.mx.RUnlock()
_, running := e.started[name]
return running
}
// Err returns any error encountered by the named controller. The returned error
// is always nil if the named controller is running.
func (e *Engine) Err(name string) error {
e.mx.RLock()
defer e.mx.RUnlock()
return e.errors[name]
}
// Stop the named controller.
func (e *Engine) Stop(name string) {
e.done(name, nil)
}
func (e *Engine) done(name string, err error) {
e.mx.Lock()
defer e.mx.Unlock()
stop, ok := e.started[name]
if ok {
stop()
delete(e.started, name)
}
// Don't overwrite the first error if done is called multiple times.
if e.errors[name] != nil {
return
}
e.errors[name] = err
}
// Watch an object.
type Watch struct {
kind client.Object
handler handler.EventHandler
predicates []predicate.Predicate
}
// For returns a Watch for the supplied kind of object. Events will be handled
// by the supplied EventHandler, and may be filtered by the supplied predicates.
func For(kind client.Object, h handler.EventHandler, p ...predicate.Predicate) Watch {
return Watch{kind: kind, handler: h, predicates: p}
}
// Start the named controller. Each controller is started with its own cache
// whose lifecycle is coupled to the controller. The controller is started with
// the supplied options, and configured with the supplied watches. Start does
// not block.
func (e *Engine) Start(name string, o controller.Options, w ...Watch) error {
if e.IsRunning(name) {
return nil
}
ctx, stop := context.WithCancel(context.Background())
e.mx.Lock()
e.started[name] = stop
e.errors[name] = nil
e.mx.Unlock()
// Each controller gets its own cache because there's currently no way to
// stop an informer. In practice a controller-runtime cache is a map of
// kinds to informers. If we delete the CRD for a kind we need to stop the
// relevant informer, or it will spew errors about the kind not existing. We
// work around this by stopping the entire cache.
ca, err := e.newCache(e.mgr.GetConfig(), cache.Options{Scheme: e.mgr.GetScheme(), Mapper: e.mgr.GetRESTMapper()})
if err != nil {
return errors.Wrap(err, errCreateCache)
}
ctrl, err := e.newCtrl(name, e.mgr, o)
if err != nil {
return errors.Wrap(err, errCreateController)
}
for _, wt := range w {
if err := ctrl.Watch(source.NewKindWithCache(wt.kind, ca), wt.handler, wt.predicates...); err != nil {
return errors.Wrap(err, errWatch)
}
}
go func() {
<-e.mgr.Elected()
e.done(name, errors.Wrap(ca.Start(ctx), errCrashCache))
}()
go func() {
<-e.mgr.Elected()
e.done(name, errors.Wrap(ctrl.Start(ctx), errCrashController))
}()
return nil
}

View File

@ -1,186 +0,0 @@
/*
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 controller
import (
"context"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/source"
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
type MockCache struct {
cache.Cache
MockStart func(stop context.Context) error
}
func (c *MockCache) Start(stop context.Context) error {
return c.MockStart(stop)
}
type MockController struct {
controller.Controller
MockStart func(stop context.Context) error
MockWatch func(s source.Source, h handler.EventHandler, p ...predicate.Predicate) error
}
func (c *MockController) Start(stop context.Context) error {
return c.MockStart(stop)
}
func (c *MockController) Watch(s source.Source, h handler.EventHandler, p ...predicate.Predicate) error {
return c.MockWatch(s, h, p...)
}
func TestEngine(t *testing.T) {
errBoom := errors.New("boom")
type args struct {
name string
o controller.Options
w []Watch
}
type want struct {
err error
crash error
}
cases := map[string]struct {
reason string
e *Engine
args args
want want
}{
"NewCacheError": {
reason: "Errors creating a new cache should be returned",
e: NewEngine(&fake.Manager{},
WithNewCacheFn(func(*rest.Config, cache.Options) (cache.Cache, error) { return nil, errBoom }),
),
args: args{
name: "coolcontroller",
},
want: want{
err: errors.Wrap(errBoom, errCreateCache),
},
},
"NewControllerError": {
reason: "Errors creating a new controller should be returned",
e: NewEngine(&fake.Manager{},
WithNewCacheFn(func(*rest.Config, cache.Options) (cache.Cache, error) { return nil, nil }),
WithNewControllerFn(func(string, manager.Manager, controller.Options) (controller.Controller, error) { return nil, errBoom }),
),
args: args{
name: "coolcontroller",
},
want: want{
err: errors.Wrap(errBoom, errCreateController),
},
},
"WatchError": {
reason: "Errors adding a watch should be returned",
e: NewEngine(&fake.Manager{},
WithNewCacheFn(func(*rest.Config, cache.Options) (cache.Cache, error) { return nil, nil }),
WithNewControllerFn(func(string, manager.Manager, controller.Options) (controller.Controller, error) {
c := &MockController{MockWatch: func(source.Source, handler.EventHandler, ...predicate.Predicate) error { return errBoom }}
return c, nil
}),
),
args: args{
name: "coolcontroller",
w: []Watch{For(&fake.Managed{}, nil)},
},
want: want{
err: errors.Wrap(errBoom, errWatch),
},
},
"CacheCrashError": {
reason: "Errors starting or running a cache should be returned",
e: NewEngine(&fake.Manager{},
WithNewCacheFn(func(*rest.Config, cache.Options) (cache.Cache, error) {
c := &MockCache{MockStart: func(stop context.Context) error { return errBoom }}
return c, nil
}),
WithNewControllerFn(func(string, manager.Manager, controller.Options) (controller.Controller, error) {
c := &MockController{MockStart: func(stop context.Context) error {
return nil
}}
return c, nil
}),
),
args: args{
name: "coolcontroller",
},
want: want{
crash: errors.Wrap(errBoom, errCrashCache),
},
},
"ControllerCrashError": {
reason: "Errors starting or running a controller should be returned",
e: NewEngine(&fake.Manager{},
WithNewCacheFn(func(*rest.Config, cache.Options) (cache.Cache, error) {
c := &MockCache{MockStart: func(stop context.Context) error {
return nil
}}
return c, nil
}),
WithNewControllerFn(func(string, manager.Manager, controller.Options) (controller.Controller, error) {
c := &MockController{MockStart: func(stop context.Context) error {
return errBoom
}}
return c, nil
}),
),
args: args{
name: "coolcontroller",
},
want: want{
crash: errors.Wrap(errBoom, errCrashController),
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
err := tc.e.Start(tc.args.name, tc.args.o, tc.args.w...)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\ne.Start(...): -want error, +got error:\n%s", tc.reason, diff)
}
// Give the goroutines a little time to return an error. If this
// becomes flaky or time consuming we could use a ticker instead.
time.Sleep(100 * time.Millisecond)
tc.e.Stop(tc.args.name)
if diff := cmp.Diff(tc.want.crash, tc.e.Err(tc.args.name), test.EquateErrors()); diff != "" {
t.Errorf("\n%s\ne.Err(...): -want error, +got error:\n%s", tc.reason, diff)
}
})
}
}

15
pkg/controller/gate.go Normal file
View File

@ -0,0 +1,15 @@
package controller
import (
"k8s.io/apimachinery/pkg/runtime/schema"
)
// A Gate is an interface to allow reconcilers to delay a callback until a set of GVKs are set to true inside the gate.
type Gate interface {
// Register to call a callback function when all given GVKs are marked true. If the callback is unblocked, the
// registration is removed.
Register(callback func(), gvks ...schema.GroupVersionKind)
// Set marks the associated condition to the given value. If the condition is already set as
// that value, then this is a no-op. Returns true if there was an update detected.
Set(gvk schema.GroupVersionKind, ready bool) bool
}

110
pkg/controller/options.go Normal file
View File

@ -0,0 +1,110 @@
/*
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.
*/
// Package controller configures controller options.
package controller
import (
"crypto/tls"
"time"
"sigs.k8s.io/controller-runtime/pkg/controller"
"github.com/crossplane/crossplane-runtime/pkg/feature"
"github.com/crossplane/crossplane-runtime/pkg/logging"
"github.com/crossplane/crossplane-runtime/pkg/ratelimiter"
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
"github.com/crossplane/crossplane-runtime/pkg/statemetrics"
)
// DefaultOptions returns a functional set of options with conservative
// defaults.
func DefaultOptions() Options {
return Options{
Logger: logging.NewNopLogger(),
GlobalRateLimiter: ratelimiter.NewGlobal(1),
PollInterval: 1 * time.Minute,
MaxConcurrentReconciles: 1,
Features: &feature.Flags{},
}
}
// Options frequently used by most Crossplane controllers.
type Options struct {
// The Logger controllers should use.
Logger logging.Logger
// The GlobalRateLimiter used by this controller manager. The rate of
// reconciles across all controllers will be subject to this limit.
GlobalRateLimiter ratelimiter.RateLimiter
// PollInterval at which each controller should speculatively poll to
// determine whether it has work to do.
PollInterval time.Duration
// MaxConcurrentReconciles for each controller.
MaxConcurrentReconciles int
// Features that should be enabled.
Features *feature.Flags
// ESSOptions for External Secret Stores.
ESSOptions *ESSOptions
// MetricOptions for recording metrics.
MetricOptions *MetricOptions
// ChangeLogOptions for recording change logs.
ChangeLogOptions *ChangeLogOptions
// Gate implements a gated function callback pattern.
Gate Gate
}
// ForControllerRuntime extracts options for controller-runtime.
func (o Options) ForControllerRuntime() controller.Options {
recoverPanic := true
return controller.Options{
MaxConcurrentReconciles: o.MaxConcurrentReconciles,
RateLimiter: ratelimiter.NewController(),
RecoverPanic: &recoverPanic,
}
}
// ESSOptions for External Secret Stores.
type ESSOptions struct {
TLSConfig *tls.Config
TLSSecretName *string
}
// MetricOptions for recording metrics.
type MetricOptions struct {
// PollStateMetricInterval at which each controller should record state
PollStateMetricInterval time.Duration
// MetricsRecorder to use for recording metrics.
MRMetrics managed.MetricRecorder
// MRStateMetrics to use for recording state metrics.
MRStateMetrics *statemetrics.MRStateMetrics
}
// ChangeLogOptions for recording changes to managed resources into the change
// logs.
type ChangeLogOptions struct {
ChangeLogger managed.ChangeLogger
}

166
pkg/errors/errors.go Normal file
View File

@ -0,0 +1,166 @@
/*
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.
*/
// Package errors is a github.com/pkg/errors compatible API for native errors.
// It includes only the subset of the github.com/pkg/errors API that is used by
// the Crossplane project.
package errors
import (
"errors"
"fmt"
kerrors "k8s.io/apimachinery/pkg/util/errors"
)
// New returns an error that formats as the given text. Each call to New returns
// a distinct error value even if the text is identical.
func New(text string) error { return errors.New(text) }
// Is reports whether any error in err's chain matches target.
//
// The chain consists of err itself followed by the sequence of errors obtained
// by repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
//
// An error type might provide an Is method so it can be treated as equivalent
// to an existing error. For example, if MyError defines
//
// func (m MyError) Is(target error) bool { return target == fs.ErrExist }
//
// then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for
// an example in the standard library.
func Is(err, target error) bool { return errors.Is(err, target) }
// As finds the first error in err's chain that matches target, and if so, sets
// target to that error value and returns true. Otherwise, it returns false.
//
// The chain consists of err itself followed by the sequence of errors obtained
// by repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the
// value pointed to by target, or if the error has a method As(any) bool
// such that As(target) returns true. In the latter case, the As method is
// responsible for setting target.
//
// An error type might provide an As method so it can be treated as if it were a
// different error type.
//
// As panics if target is not a non-nil pointer to either a type that implements
// error, or to any interface type.
func As(err error, target any) bool { return errors.As(err, target) }
// Unwrap returns the result of calling the Unwrap method on err, if err's type
// contains an Unwrap method returning error. Otherwise, Unwrap returns nil.
func Unwrap(err error) error { return errors.Unwrap(err) }
// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// If the format specifier includes a %w verb with an error operand, the
// returned error will implement an Unwrap method returning the operand. It is
// invalid to include more than one %w verb or to supply it with an operand that
// does not implement the error interface. The %w verb is otherwise a synonym
// for %v.
func Errorf(format string, a ...any) error { return fmt.Errorf(format, a...) }
// WithMessage annotates err with a new message. If err is nil, WithMessage
// returns nil.
func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %w", message, err)
}
// WithMessagef annotates err with the format specifier. If err is nil,
// WithMessagef returns nil.
func WithMessagef(err error, format string, args ...any) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)
}
// Wrap is an alias for WithMessage.
func Wrap(err error, message string) error {
return WithMessage(err, message)
}
// Wrapf is an alias for WithMessagef.
func Wrapf(err error, format string, args ...any) error {
return WithMessagef(err, format, args...)
}
// Cause calls Unwrap on each error it finds. It returns the first error it
// finds that does not have an Unwrap method - i.e. the first error that was not
// the result of a Wrap call, a Wrapf call, or an Errorf call with %w wrapping.
func Cause(err error) error {
type wrapped interface {
Unwrap() error
}
for err != nil {
w, ok := err.(wrapped)
if !ok {
return err
}
err = w.Unwrap()
}
return err
}
// MultiError is an error that wraps multiple errors.
type MultiError interface {
error
Unwrap() []error
}
// Join returns an error that wraps the given errors. Any nil error values are
// discarded. Join returns nil if errs contains no non-nil values. The error
// formats as the concatenation of the strings obtained by calling the Error
// method of each element of errs and formatting like:
//
// [first error, second error, third error]
//
// Note: aggregating errors should not be the default. Usually, return only the
// first error, and only aggregate if there is clear value to the user.
func Join(errs ...error) MultiError {
err := kerrors.NewAggregate(errs)
if err == nil {
return nil
}
return multiError{aggregate: err}
}
type multiError struct {
aggregate kerrors.Aggregate
}
func (m multiError) Error() string {
return m.aggregate.Error()
}
func (m multiError) Unwrap() []error {
return m.aggregate.Errors()
}

128
pkg/errors/errors_test.go Normal file
View File

@ -0,0 +1,128 @@
/*
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.
*/
package errors
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
func TestWrap(t *testing.T) {
type args struct {
err error
message string
}
cases := map[string]struct {
args args
want error
}{
"NilError": {
args: args{
err: nil,
message: "very useful context",
},
want: nil,
},
"NonNilError": {
args: args{
err: New("boom"),
message: "very useful context",
},
want: Errorf("very useful context: %w", New("boom")),
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := Wrap(tc.args.err, tc.args.message)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("Wrap(...): -want, +got:\n%s", diff)
}
})
}
}
func TestWrapf(t *testing.T) {
type args struct {
err error
message string
args []any
}
cases := map[string]struct {
args args
want error
}{
"NilError": {
args: args{
err: nil,
message: "very useful context",
},
want: nil,
},
"NonNilError": {
args: args{
err: New("boom"),
message: "very useful context about %s",
args: []any{"ducks"},
},
want: Errorf("very useful context about %s: %w", "ducks", New("boom")),
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := Wrapf(tc.args.err, tc.args.message, tc.args.args...)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("Wrapf(...): -want, +got:\n%s", diff)
}
})
}
}
func TestCause(t *testing.T) {
cases := map[string]struct {
err error
want error
}{
"NilError": {
err: nil,
want: nil,
},
"BareError": {
err: New("boom"),
want: New("boom"),
},
"WrappedError": {
err: Wrap(Wrap(New("boom"), "interstitial context"), "very important context"),
want: New("boom"),
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := Cause(tc.err)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("Cause(...): -want, +got:\n%s", diff)
}
})
}
}

50
pkg/errors/reconcile.go Normal file
View File

@ -0,0 +1,50 @@
/*
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 errors
import (
"context"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// SilentlyRequeueOnConflict returns a requeue result and silently drops the
// error if it is a Kubernetes conflict error from the optimistic concurrency
// protocol.
func SilentlyRequeueOnConflict(result reconcile.Result, err error) (reconcile.Result, error) {
if kerrors.IsConflict(Cause(err)) {
return reconcile.Result{Requeue: true}, nil
}
return result, err
}
// WithSilentRequeueOnConflict wraps a Reconciler and silently drops conflict
// errors and requeues instead.
func WithSilentRequeueOnConflict(r reconcile.Reconciler) reconcile.Reconciler {
return &silentlyRequeueOnConflict{Reconciler: r}
}
type silentlyRequeueOnConflict struct {
reconcile.Reconciler
}
func (r *silentlyRequeueOnConflict) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
result, err := r.Reconciler.Reconcile(ctx, req)
return SilentlyRequeueOnConflict(result, err)
}

View File

@ -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 errors
import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
func TestSilentlyRequeueOnConflict(t *testing.T) {
type args struct {
result reconcile.Result
err error
}
type want struct {
result reconcile.Result
err error
}
tests := []struct {
reason string
args args
want want
}{
{
reason: "nil error",
args: args{
result: reconcile.Result{RequeueAfter: time.Second},
},
want: want{
result: reconcile.Result{RequeueAfter: time.Second},
},
},
{
reason: "other error",
args: args{
result: reconcile.Result{RequeueAfter: time.Second},
err: New("some other error"),
},
want: want{
result: reconcile.Result{RequeueAfter: time.Second},
err: New("some other error"),
},
},
{
reason: "conflict error",
args: args{
result: reconcile.Result{RequeueAfter: time.Second},
err: kerrors.NewConflict(schema.GroupResource{Group: "nature", Resource: "stones"}, "foo", New("nested error")),
},
want: want{
result: reconcile.Result{Requeue: true},
},
},
{
reason: "nested conflict error",
args: args{
result: reconcile.Result{RequeueAfter: time.Second},
err: Wrap(
kerrors.NewConflict(schema.GroupResource{Group: "nature", Resource: "stones"}, "foo", New("nested error")),
"outer error"),
},
want: want{
result: reconcile.Result{Requeue: true},
},
},
}
for _, tt := range tests {
t.Run(tt.reason, func(t *testing.T) {
got, err := SilentlyRequeueOnConflict(tt.args.result, tt.args.err)
if diff := cmp.Diff(tt.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nIgnoreConflict(...): -want error, +got error:\n%s", tt.reason, diff)
}
if diff := cmp.Diff(tt.want.result, got); diff != "" {
t.Errorf("\n%s\nIgnoreConflict(...): -want result, +got result:\n%s", tt.reason, diff)
}
})
}
}

View File

@ -27,7 +27,7 @@ type Type string
// Event types. See below for valid types.
// https://godoc.org/k8s.io/client-go/tools/record#EventRecorder
var (
const (
TypeNormal Type = "Normal"
TypeWarning Type = "Warning"
)
@ -52,6 +52,7 @@ func Normal(r Reason, message string, keysAndValues ...string) Event {
Annotations: map[string]string{},
}
sliceMap(keysAndValues, e.Annotations)
return e
}
@ -64,6 +65,7 @@ func Warning(r Reason, err error, keysAndValues ...string) Event {
Annotations: map[string]string{},
}
sliceMap(keysAndValues, e.Annotations)
return e
}
@ -77,17 +79,27 @@ type Recorder interface {
type APIRecorder struct {
kube record.EventRecorder
annotations map[string]string
filterFns []FilterFn
}
// FilterFn is a function used to filter events.
// It should return false when events should not be sent.
type FilterFn func(obj runtime.Object, e Event) bool
// NewAPIRecorder returns an APIRecorder that records Kubernetes events to an
// APIServer using the supplied EventRecorder.
func NewAPIRecorder(r record.EventRecorder) *APIRecorder {
return &APIRecorder{kube: r, annotations: map[string]string{}}
func NewAPIRecorder(r record.EventRecorder, fns ...FilterFn) *APIRecorder {
return &APIRecorder{kube: r, annotations: map[string]string{}, filterFns: fns}
}
// Event records the supplied event.
func (r *APIRecorder) Event(obj runtime.Object, e Event) {
r.kube.AnnotatedEventf(obj, r.annotations, string(e.Type), string(e.Reason), e.Message)
for _, filter := range r.filterFns {
if filter(obj, e) {
return
}
}
r.kube.AnnotatedEventf(obj, r.annotations, string(e.Type), string(e.Reason), "%s", e.Message)
}
// WithAnnotations returns a new *APIRecorder that includes the supplied
@ -97,7 +109,9 @@ func (r *APIRecorder) WithAnnotations(keysAndValues ...string) Recorder {
for k, v := range r.annotations {
ar.annotations[k] = v
}
sliceMap(keysAndValues, ar.annotations)
return ar
}

View File

@ -24,11 +24,11 @@ import (
)
func TestSliceMap(t *testing.T) {
type args struct {
from []string
to map[string]string
}
cases := map[string]struct {
reason string
args args
@ -86,5 +86,4 @@ func TestSliceMap(t *testing.T) {
}
})
}
}

55
pkg/feature/feature.go Normal file
View File

@ -0,0 +1,55 @@
/*
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.
*/
// Package feature contains utilities for managing Crossplane features.
package feature
import (
"sync"
)
// A Flag enables a particular feature.
type Flag string
// Flags that are enabled. The zero value - i.e. &feature.Flags{} - is usable.
type Flags struct {
m sync.RWMutex
enabled map[Flag]bool
}
// Enable a feature flag.
func (fs *Flags) Enable(f Flag) {
fs.m.Lock()
if fs.enabled == nil {
fs.enabled = make(map[Flag]bool)
}
fs.enabled[f] = true
fs.m.Unlock()
}
// Enabled returns true if the supplied feature flag is enabled.
func (fs *Flags) Enabled(f Flag) bool {
if fs == nil {
return false
}
fs.m.RLock()
defer fs.m.RUnlock()
return fs.enabled[f]
}

View File

@ -0,0 +1,61 @@
/*
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.
*/
package feature
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestEnable(t *testing.T) {
var cool Flag = "cool"
t.Run("EnableMutatesZeroValue", func(t *testing.T) {
f := &Flags{}
f.Enable(cool)
want := true
got := f.Enabled(cool)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("f.Enabled(...): -want, +got:\n%s", diff)
}
})
t.Run("EnabledOnEmptyFlagsReturnsFalse", func(t *testing.T) {
f := &Flags{}
want := false
got := f.Enabled(cool)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("f.Enabled(...): -want, +got:\n%s", diff)
}
})
t.Run("EnabledOnNilReturnsFalse", func(t *testing.T) {
var f *Flags
want := false
got := f.Enabled(cool)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("f.Enabled(...): -want, +got:\n%s", diff)
}
})
}

27
pkg/feature/features.go Normal file
View File

@ -0,0 +1,27 @@
/*
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 feature
// EnableBetaManagementPolicies enables beta support for
// Management Policies. See the below design for more details.
// https://github.com/crossplane/crossplane/pull/3531
const EnableBetaManagementPolicies Flag = "EnableBetaManagementPolicies"
// EnableAlphaChangeLogs enables alpha support for capturing change logs during
// reconciliation. See the following design for more details:
// https://github.com/crossplane/crossplane/pull/5822
const EnableAlphaChangeLogs Flag = "EnableAlphaChangeLogs"

View File

@ -48,7 +48,7 @@ import (
"strings"
"unicode/utf8"
"github.com/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
// A SegmentType within a field path; either a field within an object, or an
@ -78,10 +78,11 @@ func (sg Segments) String() string {
for _, s := range sg {
switch s.Type {
case SegmentField:
if strings.ContainsRune(s.Field, period) {
if s.Field == wildcard || strings.ContainsRune(s.Field, period) {
b.WriteString(fmt.Sprintf("[%s]", s.Field))
continue
}
b.WriteString(fmt.Sprintf(".%s", s.Field))
case SegmentIndex:
b.WriteString(fmt.Sprintf("[%d]", s.Index))
@ -120,9 +121,9 @@ func Parse(path string) (Segments, error) {
go l.run()
segments := make(Segments, 0, 1)
for i := range l.items {
// We're only worried about names, not separators.
switch i.typ { // nolint:exhaustive
switch i.typ { //nolint:exhaustive // We're only worried about names, not separators.
case itemField:
segments = append(segments, Field(i.val))
case itemFieldOrIndex:
@ -131,6 +132,7 @@ func Parse(path string) (Segments, error) {
return nil, errors.Errorf("%s at position %d", i.val, i.pos)
}
}
return segments, nil
}
@ -138,6 +140,8 @@ const (
period = '.'
leftBracket = '['
rightBracket = ']'
wildcard = "*"
)
type itemType int
@ -173,6 +177,7 @@ func (l *lexer) run() {
for state := lexField; state != nil; {
state = state(l)
}
close(l.items)
}
@ -181,11 +186,13 @@ func (l *lexer) emit(t itemType) {
if l.pos <= l.start {
return
}
l.items <- item{typ: t, pos: l.start, val: l.input[l.start:l.pos]}
l.start = l.pos
}
func (l *lexer) errorf(pos int, format string, args ...interface{}) stateFn {
func (l *lexer) errorf(pos int, format string, args ...any) stateFn {
l.items <- item{typ: itemError, pos: pos, val: fmt.Sprintf(format, args...)}
return nil
}
@ -201,12 +208,14 @@ func lexField(l *lexer) stateFn {
case leftBracket:
l.pos += i
l.emit(itemField)
return lexLeftBracket
// A period indicates the end of the field name.
case period:
l.pos += i
l.emit(itemField)
return lexPeriod
}
}
@ -215,6 +224,7 @@ func lexField(l *lexer) stateFn {
l.pos = len(l.input)
l.emit(itemField)
l.emit(itemEOL)
return nil
}
@ -233,6 +243,7 @@ func lexPeriod(l *lexer) stateFn {
if r == period {
return l.errorf(l.pos, "unexpected %q", period)
}
if r == leftBracket {
return l.errorf(l.pos, "unexpected %q", leftBracket)
}
@ -248,6 +259,7 @@ func lexLeftBracket(l *lexer) stateFn {
l.pos += utf8.RuneLen(leftBracket)
l.emit(itemLeftBracket)
return lexFieldOrIndex
}
@ -271,11 +283,13 @@ func lexFieldOrIndex(l *lexer) stateFn {
// Periods are not considered field separators when we're inside brackets.
l.pos += rbi
l.emit(itemFieldOrIndex)
return lexRightBracket
}
func lexRightBracket(l *lexer) stateFn {
l.pos += utf8.RuneLen(rightBracket)
l.emit(itemRightBracket)
return lexField
}

View File

@ -22,8 +22,8 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
@ -56,6 +56,15 @@ func TestSegments(t *testing.T) {
},
want: "data[.config.yml]",
},
"Wildcard": {
s: Segments{
Field("spec"),
Field("containers"),
FieldOrIndex("*"),
Field("name"),
},
want: "spec.containers[*].name",
},
}
for name, tc := range cases {
@ -63,7 +72,6 @@ func TestSegments(t *testing.T) {
if diff := cmp.Diff(tc.want, tc.s.String()); diff != "" {
t.Errorf("s.String(): -want, +got:\n %s", diff)
}
})
}
}
@ -291,6 +299,7 @@ func TestParse(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\nParse(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.s, got); diff != "" {
t.Errorf("\nParse(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}

118
pkg/fieldpath/merge.go Normal file
View File

@ -0,0 +1,118 @@
/*
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.
*/
package fieldpath
import (
"reflect"
"dario.cat/mergo"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
const (
errInvalidMerge = "failed to merge values"
)
// MergeValue of the receiver p at the specified field path with the supplied
// value according to supplied merge options.
func (p *Paved) MergeValue(path string, value any, mo *xpv1.MergeOptions) error {
dst, err := p.GetValue(path)
if IsNotFound(err) || mo == nil {
dst = nil
} else if err != nil {
return err
}
dst, err = merge(dst, value, mo)
if err != nil {
return err
}
return p.SetValue(path, dst)
}
// merges the given src onto the given dst.
// dst and src must have the same type.
// If a nil merge options is supplied, the default behavior is MergeOptions'
// default behavior. If dst or src is nil, src is returned
// (i.e., dst replaced by src).
func merge(dst, src any, mergeOptions *xpv1.MergeOptions) (any, error) {
// because we are merging values of a field, which can be a slice, and
// because mergo currently supports merging only maps or structs,
// we wrap the argument to be passed to mergo.Merge in a map.
const keyArg = "arg"
argWrap := func(arg any) map[string]any {
return map[string]any{
keyArg: arg,
}
}
if dst == nil || src == nil {
return src, nil // no merge, replace
}
// TODO(aru): we may provide an extra MergeOption to also append duplicates of slice elements
// but, by default, do not append duplicate slice items if MergeOptions.AppendSlice is set
if mergeOptions.IsAppendSlice() {
src = removeSourceDuplicates(dst, src)
}
mDst := argWrap(dst)
// use merge semantics with the configured merge options to obtain the target dst value
if err := mergo.Merge(&mDst, argWrap(src), mergeOptions.MergoConfiguration()...); err != nil {
return nil, errors.Wrap(err, errInvalidMerge)
}
return mDst[keyArg], nil
}
func removeSourceDuplicates(dst, src any) any {
sliceDst, sliceSrc := reflect.ValueOf(dst), reflect.ValueOf(src)
if sliceDst.Kind() == reflect.Ptr {
sliceDst = sliceDst.Elem()
}
if sliceSrc.Kind() == reflect.Ptr {
sliceSrc = sliceSrc.Elem()
}
if sliceDst.Kind() != reflect.Slice || sliceSrc.Kind() != reflect.Slice {
return src
}
result := reflect.New(sliceSrc.Type()).Elem() // we will not modify src
for i := range sliceSrc.Len() {
itemSrc := sliceSrc.Index(i)
found := false
for j := 0; j < sliceDst.Len() && !found; j++ {
// if src item is found in the dst array
if reflect.DeepEqual(itemSrc.Interface(), sliceDst.Index(j).Interface()) {
found = true
}
}
if !found {
// then put src item into result
result = reflect.Append(result, itemSrc)
}
}
return result.Interface()
}

219
pkg/fieldpath/merge_test.go Normal file
View File

@ -0,0 +1,219 @@
/*
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.
*/
package fieldpath
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/util/json"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
func TestMergeValue(t *testing.T) {
const (
pathTest = "a"
valSrc = "e1-from-source"
valSrc2 = "e1-from-source-2"
valDst = "e1-from-destination"
)
formatArr := func(arr []string) string {
return fmt.Sprintf(`{"%s": ["%s"]}`, pathTest, strings.Join(arr, `", "`))
}
formatMap := func(val string) string {
return fmt.Sprintf(`{"%s": {"%s": "%s"}}`, pathTest, pathTest, val)
}
appendArr := func(dst, src []string) []string {
return reflect.AppendSlice(reflect.ValueOf(dst), reflect.ValueOf(src)).Interface().([]string)
}
arrSrc := []string{valSrc}
fnMapSrc := func() map[string]any {
return map[string]any{pathTest: valSrc}
}
arrDst := []string{valDst}
fnMapDst := func() map[string]any {
return map[string]any{pathTest: map[string]any{pathTest: valDst}}
}
valFalse, valTrue := false, true
type fields struct {
object map[string]any
}
type args struct {
path string
value any
mo *xpv1.MergeOptions
}
type want struct {
serialized string
err error
}
tests := map[string]struct {
reason string
fields fields
args args
want want
}{
"MergeArrayNoMergeOptions": {
reason: "If no merge options are given, default is to override an array",
fields: fields{
object: map[string]any{
pathTest: valDst,
},
},
args: args{
path: pathTest,
value: arrSrc,
},
want: want{
serialized: formatArr(arrSrc),
},
},
"MergeArrayNoAppend": {
reason: "If MergeOptions.AppendSlice is false, an array should be overridden when merging",
fields: fields{
object: map[string]any{
pathTest: arrDst,
},
},
args: args{
path: pathTest,
value: arrSrc,
mo: &xpv1.MergeOptions{
AppendSlice: &valFalse,
},
},
want: want{
serialized: formatArr(arrSrc),
},
},
"MergeArrayAppend": {
reason: "If MergeOptions.AppendSlice is true, dst array should be merged with the src array",
fields: fields{
object: map[string]any{
pathTest: arrDst,
},
},
args: args{
path: pathTest,
value: arrSrc,
mo: &xpv1.MergeOptions{
AppendSlice: &valTrue,
},
},
want: want{
serialized: formatArr(appendArr(arrDst, arrSrc)),
},
},
"MergeArrayAppendDuplicate": {
reason: "If MergeOptions.AppendSlice is true, dst array should be merged with the src array not allowing duplicates",
fields: fields{
object: map[string]any{
pathTest: []string{valDst, valSrc},
},
},
args: args{
path: pathTest,
value: []string{valSrc, valSrc2},
mo: &xpv1.MergeOptions{
AppendSlice: &valTrue,
},
},
want: want{
serialized: formatArr([]string{valDst, valSrc, valSrc2}),
},
},
"MergeMapNoMergeOptions": {
reason: "If no merge options are given, default is to override a map key",
fields: fields{
object: fnMapDst(),
},
args: args{
path: pathTest,
value: fnMapSrc(),
},
want: want{
serialized: formatMap(valSrc),
},
},
"MergeMapNoKeep": {
reason: "If MergeOptions.KeepMapValues is false, a map key should be overridden",
fields: fields{
object: fnMapDst(),
},
args: args{
path: pathTest,
value: fnMapSrc(),
mo: &xpv1.MergeOptions{
KeepMapValues: &valFalse,
},
},
want: want{
serialized: formatMap(valSrc),
},
},
"MergeMapKeep": {
reason: "If MergeOptions.KeepMapValues is true, a dst map key should preserve its value",
fields: fields{
object: fnMapDst(),
},
args: args{
path: pathTest,
value: fnMapSrc(),
mo: &xpv1.MergeOptions{
KeepMapValues: &valTrue,
},
},
want: want{
serialized: formatMap(valDst),
},
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
want := make(map[string]any)
if err := json.Unmarshal([]byte(tc.want.serialized), &want); err != nil {
t.Fatalf("Test case error: Unable to unmarshall JSON doc: %v", err)
}
p := &Paved{
object: tc.fields.object,
}
err := p.MergeValue(tc.args.path, tc.args.value, tc.args.mo)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.MergeValue(%s, %v): %s: -want error, +got error:\n%s",
tc.args.path, tc.args.value, tc.reason, diff)
}
if diff := cmp.Diff(want, p.object); diff != "" {
t.Fatalf("\np.MergeValue(%s, %v): %s: -want, +got:\n%s",
tc.args.path, tc.args.value, tc.reason, diff)
}
})
}
}

View File

@ -17,16 +17,22 @@ limitations under the License.
package fieldpath
import (
"github.com/pkg/errors"
"strconv"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/json"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
type errNotFound struct {
// DefaultMaxFieldPathIndex is the max allowed index in a field path.
const DefaultMaxFieldPathIndex = 1024
type notFoundError struct {
error
}
func (e errNotFound) IsNotFound() bool {
func (e notFoundError) IsNotFound() bool {
return true
}
@ -38,24 +44,46 @@ func IsNotFound(err error) bool {
_, ok := cause.(interface {
IsNotFound() bool
})
return ok
}
// A Paved JSON object supports getting and setting values by their field path.
type Paved struct {
object map[string]interface{}
object map[string]any
maxFieldPathIndex uint
}
// PavedOption can be used to configure a Paved behavior.
type PavedOption func(paved *Paved)
// PaveObject paves a runtime.Object, making it possible to get and set values
// by field path.
func PaveObject(o runtime.Object) (*Paved, error) {
// by field path. o must be a non-nil pointer to an object.
func PaveObject(o runtime.Object, opts ...PavedOption) (*Paved, error) {
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(o)
return Pave(u), errors.Wrap(err, "cannot convert object to unstructured data")
return Pave(u, opts...), errors.Wrap(err, "cannot convert object to unstructured data")
}
// Pave a JSON object, making it possible to get and set values by field path.
func Pave(object map[string]interface{}) *Paved {
return &Paved{object: object}
func Pave(object map[string]any, opts ...PavedOption) *Paved {
p := &Paved{object: object, maxFieldPathIndex: DefaultMaxFieldPathIndex}
for _, opt := range opts {
opt(p)
}
return p
}
// WithMaxFieldPathIndex returns a PavedOption that sets the max allowed index for field paths, 0 means no limit.
func WithMaxFieldPathIndex(maxIndex uint) PavedOption {
return func(paved *Paved) {
paved.maxFieldPathIndex = maxIndex
}
}
func (p *Paved) maxFieldPathIndexEnabled() bool {
return p.maxFieldPathIndex > 0
}
// MarshalJSON to the underlying object.
@ -69,49 +97,61 @@ func (p *Paved) UnmarshalJSON(data []byte) error {
}
// UnstructuredContent returns the JSON serialisable content of this Paved.
func (p *Paved) UnstructuredContent() map[string]interface{} {
func (p *Paved) UnstructuredContent() map[string]any {
if p.object == nil {
return make(map[string]interface{})
return make(map[string]any)
}
return p.object
}
// SetUnstructuredContent sets the JSON serialisable content of this Paved.
func (p *Paved) SetUnstructuredContent(content map[string]interface{}) {
func (p *Paved) SetUnstructuredContent(content map[string]any) {
p.object = content
}
func (p *Paved) getValue(s Segments) (interface{}, error) {
var it interface{} = p.object
func (p *Paved) getValue(s Segments) (any, error) {
return getValueFromInterface(p.object, s)
}
func getValueFromInterface(it any, s Segments) (any, error) {
for i, current := range s {
final := i == len(s)-1
switch current.Type {
case SegmentIndex:
array, ok := it.([]interface{})
array, ok := it.([]any)
if !ok {
return nil, errors.Errorf("%s: not an array", s[:i])
}
if int(current.Index) >= len(array) {
return nil, errNotFound{errors.Errorf("%s: no such element", s[:i+1])}
if current.Index >= uint(len(array)) {
return nil, notFoundError{errors.Errorf("%s: no such element", s[:i+1])}
}
if final {
return array[current.Index], nil
}
it = array[current.Index]
it = array[current.Index]
case SegmentField:
object, ok := it.(map[string]interface{})
if !ok {
switch object := it.(type) {
case map[string]any:
v, ok := object[current.Field]
if !ok {
return nil, notFoundError{errors.Errorf("%s: no such field", s[:i+1])}
}
if final {
return v, nil
}
it = object[current.Field]
case nil:
return nil, notFoundError{errors.Errorf("%s: expected map, got nil", s[:i])}
default:
return nil, errors.Errorf("%s: not an object", s[:i])
}
v, ok := object[current.Field]
if !ok {
return nil, errNotFound{errors.Errorf("%s: no such field", s[:i+1])}
}
if final {
return v, nil
}
it = object[current.Field]
}
}
@ -119,8 +159,97 @@ func (p *Paved) getValue(s Segments) (interface{}, error) {
return nil, nil
}
// ExpandWildcards expands wildcards for a given field path. It returns an
// array of field paths with expanded values. Please note that expanded paths
// depend on the input data which is paved.object.
//
// Example:
//
// For a Paved object with the following data: []byte(`{"spec":{"containers":[{"name":"cool", "image": "latest", "args": ["start", "now", "debug"]}]}}`),
// ExpandWildcards("spec.containers[*].args[*]") returns:
// []string{"spec.containers[0].args[0]", "spec.containers[0].args[1]", "spec.containers[0].args[2]"},.
func (p *Paved) ExpandWildcards(path string) ([]string, error) {
segments, err := Parse(path)
if err != nil {
return nil, errors.Wrapf(err, "cannot parse path %q", path)
}
segmentsArray, err := expandWildcards(p.object, segments)
if err != nil {
return nil, errors.Wrapf(err, "cannot expand wildcards for segments: %q", segments)
}
paths := make([]string, len(segmentsArray))
for i, s := range segmentsArray {
paths[i] = s.String()
}
return paths, nil
}
func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint:gocognit // See note below.
// Even complexity turns out to be high, it is mostly because we have duplicate
// logic for arrays and maps and a couple of error handling.
var res []Segments
it := data
for i, current := range segments {
// wildcards are regular fields with "*" as string
if current.Type == SegmentField && current.Field == wildcard {
switch mapOrArray := it.(type) {
case []any:
for ix := range mapOrArray {
expanded := make(Segments, len(segments))
copy(expanded, segments)
expanded = append(append(expanded[:i], FieldOrIndex(strconv.Itoa(ix))), expanded[i+1:]...)
r, err := expandWildcards(data, expanded)
if err != nil {
return nil, errors.Wrapf(err, "%q: cannot expand wildcards", expanded)
}
res = append(res, r...)
}
case map[string]any:
for k := range mapOrArray {
expanded := make(Segments, len(segments))
copy(expanded, segments)
expanded = append(append(expanded[:i], Field(k)), expanded[i+1:]...)
r, err := expandWildcards(data, expanded)
if err != nil {
return nil, errors.Wrapf(err, "%q: cannot expand wildcards", expanded)
}
res = append(res, r...)
}
case nil:
return nil, notFoundError{errors.Errorf("wildcard field %q is not found in the path", segments[:i])}
default:
return nil, errors.Errorf("%q: unexpected wildcard usage", segments[:i])
}
return res, nil
}
var err error
it, err = getValueFromInterface(data, segments[:i+1])
if IsNotFound(err) {
return nil, nil
}
if err != nil {
return nil, err
}
}
return append(res, segments), nil
}
// GetValue of the supplied field path.
func (p *Paved) GetValue(path string) (interface{}, error) {
func (p *Paved) GetValue(path string) (any, error) {
segments, err := Parse(path)
if err != nil {
return nil, errors.Wrapf(err, "cannot parse path %q", path)
@ -130,15 +259,17 @@ func (p *Paved) GetValue(path string) (interface{}, error) {
}
// GetValueInto the supplied type.
func (p *Paved) GetValueInto(path string, out interface{}) error {
func (p *Paved) GetValueInto(path string, out any) error {
val, err := p.GetValue(path)
if err != nil {
return err
}
js, err := json.Marshal(val)
if err != nil {
return errors.Wrap(err, "cannot marshal value to JSON")
}
return errors.Wrap(json.Unmarshal(js, out), "cannot unmarshal value from JSON")
}
@ -153,6 +284,7 @@ func (p *Paved) GetString(path string) (string, error) {
if !ok {
return "", errors.Errorf("%s: not a string", path)
}
return s, nil
}
@ -163,7 +295,7 @@ func (p *Paved) GetStringArray(path string) ([]string, error) {
return nil, err
}
a, ok := v.([]interface{})
a, ok := v.([]any)
if !ok {
return nil, errors.Errorf("%s: not an array", path)
}
@ -174,6 +306,7 @@ func (p *Paved) GetStringArray(path string) ([]string, error) {
if !ok {
return nil, errors.Errorf("%s: not an array of strings", path)
}
sa[i] = s
}
@ -187,7 +320,7 @@ func (p *Paved) GetStringObject(path string) (map[string]string, error) {
return nil, err
}
o, ok := v.(map[string]interface{})
o, ok := v.(map[string]any)
if !ok {
return nil, errors.Errorf("%s: not an object", path)
}
@ -198,8 +331,8 @@ func (p *Paved) GetStringObject(path string) (map[string]string, error) {
if !ok {
return nil, errors.Errorf("%s: not an object with string field values", path)
}
so[k] = s
so[k] = s
}
return so, nil
@ -216,31 +349,10 @@ func (p *Paved) GetBool(path string) (bool, error) {
if !ok {
return false, errors.Errorf("%s: not a bool", path)
}
return b, nil
}
// NOTE(muvaf): If there is no CRD, unstructured.Unstructured reads numbers as
// float64. However, in practice, use of float64 is discouraged and when you fetch
// an instance of a CRD whose number fields are int64, you'll get int64. So,
// it's not really possible to test this without an api-server but that's the
// actual behavior.
// GetNumber value of the supplied field path.
// Deprecated: Use of float64 is discouraged. Please use GetInteger.
// See https://github.com/kubernetes/community/blob/c9ae475/contributors/devel/sig-architecture/api-conventions.md#primitive-types
func (p *Paved) GetNumber(path string) (float64, error) {
v, err := p.GetValue(path)
if err != nil {
return 0, err
}
f, ok := v.(float64)
if !ok {
return 0, errors.Errorf("%s: not a (float64) number", path)
}
return f, nil
}
// GetInteger value of the supplied field path.
func (p *Paved) GetInteger(path string) (int64, error) {
v, err := p.GetValue(path)
@ -252,30 +364,32 @@ func (p *Paved) GetInteger(path string) (int64, error) {
if !ok {
return 0, errors.Errorf("%s: not a (int64) number", path)
}
return f, nil
}
func (p *Paved) setValue(s Segments, value interface{}) error {
func (p *Paved) setValue(s Segments, value any) error {
// We expect p.object to look like JSON data that was unmarshalled into an
// interface{} per https://golang.org/pkg/encoding/json/#Unmarshal. We
// marshal our value to JSON and unmarshal it into an interface{} to ensure
// any per https://golang.org/pkg/encoding/json/#Unmarshal. We
// marshal our value to JSON and unmarshal it into an any to ensure
// it meets these criteria before setting it within p.object.
var v interface{}
j, err := json.Marshal(value)
v, err := toValidJSON(value)
if err != nil {
return errors.Wrap(err, "cannot marshal value to JSON")
}
if err := json.Unmarshal(j, &v); err != nil {
return errors.Wrap(err, "cannot unmarshal value from JSON")
return err
}
var in interface{} = p.object
if err := p.validateSegments(s); err != nil {
return err
}
var in any = p.object
for i, current := range s {
final := i == len(s)-1
switch current.Type {
case SegmentIndex:
array, ok := in.([]interface{})
array, ok := in.([]any)
if !ok {
return errors.Errorf("%s is not an array", s[:i])
}
@ -289,7 +403,7 @@ func (p *Paved) setValue(s Segments, value interface{}) error {
in = array[current.Index]
case SegmentField:
object, ok := in.(map[string]interface{})
object, ok := in.(map[string]any)
if !ok {
return errors.Errorf("%s is not an object", s[:i])
}
@ -307,16 +421,32 @@ func (p *Paved) setValue(s Segments, value interface{}) error {
return nil
}
func prepareElement(array []interface{}, current, next Segment) {
func toValidJSON(value any) (any, error) {
var v any
j, err := json.Marshal(value)
if err != nil {
return nil, errors.Wrap(err, "cannot marshal value to JSON")
}
if err := json.Unmarshal(j, &v); err != nil {
return nil, errors.Wrap(err, "cannot unmarshal value from JSON")
}
return v, nil
}
func prepareElement(array []any, current, next Segment) {
// If this segment is not the final one and doesn't exist we need to
// create it for our next segment.
if array[current.Index] == nil {
switch next.Type {
case SegmentIndex:
array[current.Index] = make([]interface{}, next.Index+1)
array[current.Index] = make([]any, next.Index+1)
case SegmentField:
array[current.Index] = make(map[string]interface{})
array[current.Index] = make(map[string]any)
}
return
}
@ -326,28 +456,29 @@ func prepareElement(array []interface{}, current, next Segment) {
return
}
na, ok := array[current.Index].([]interface{})
na, ok := array[current.Index].([]any)
if !ok {
return
}
if int(next.Index) < len(na) {
if next.Index < uint(len(na)) {
return
}
array[current.Index] = append(na, make([]interface{}, int(next.Index)-len(na)+1)...)
array[current.Index] = append(na, make([]any, next.Index-uint(len(na))+1)...)
}
func prepareField(object map[string]interface{}, current, next Segment) {
func prepareField(object map[string]any, current, next Segment) {
// If this segment is not the final one and doesn't exist we need to
// create it for our next segment.
if _, ok := object[current.Field]; !ok {
switch next.Type {
case SegmentIndex:
object[current.Field] = make([]interface{}, next.Index+1)
object[current.Field] = make([]any, next.Index+1)
case SegmentField:
object[current.Field] = make(map[string]interface{})
object[current.Field] = make(map[string]any)
}
return
}
@ -357,27 +488,42 @@ func prepareField(object map[string]interface{}, current, next Segment) {
return
}
na, ok := object[current.Field].([]interface{})
na, ok := object[current.Field].([]any)
if !ok {
return
}
if int(next.Index) < len(na) {
if next.Index < uint(len(na)) {
return
}
object[current.Field] = append(na, make([]interface{}, int(next.Index)-len(na)+1)...)
object[current.Field] = append(na, make([]any, next.Index-uint(len(na))+1)...)
}
// SetValue at the supplied field path.
func (p *Paved) SetValue(path string, value interface{}) error {
func (p *Paved) SetValue(path string, value any) error {
segments, err := Parse(path)
if err != nil {
return errors.Wrapf(err, "cannot parse path %q", path)
}
return p.setValue(segments, value)
}
func (p *Paved) validateSegments(s Segments) error {
if !p.maxFieldPathIndexEnabled() {
return nil
}
for _, segment := range s {
if segment.Type == SegmentIndex && segment.Index > p.maxFieldPathIndex {
return errors.Errorf("index %v is greater than max allowed index %d", segment.Index, p.maxFieldPathIndex)
}
}
return nil
}
// SetString value at the supplied field path.
func (p *Paved) SetString(path, value string) error {
return p.SetValue(path, value)
@ -392,3 +538,130 @@ func (p *Paved) SetBool(path string, value bool) error {
func (p *Paved) SetNumber(path string, value float64) error {
return p.SetValue(path, value)
}
// DeleteField deletes the field from the object.
// If the path points to an entry in an array, the element
// on that index is removed and the next ones are pulled
// back. If it is a field on a map, the field is
// removed from the map.
func (p *Paved) DeleteField(path string) error {
segments, err := Parse(path)
if err != nil {
return errors.Wrapf(err, "cannot parse path %q", path)
}
return p.delete(segments)
}
func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note below.
// NOTE(muvaf): I could not reduce the cyclomatic complexity
// more than that without disturbing the reading flow.
if len(segments) == 1 {
o, err := deleteField(p.object, segments[0])
if err != nil {
return errors.Wrapf(err, "cannot delete %s", segments)
}
p.object = o.(map[string]any) //nolint:forcetypeassert // We're deleting from the root of the paved object, which is always a map[string]any.
return nil
}
var in any = p.object
for i, current := range segments {
// beforeLast is true for the element before the last one because
// slices cannot be changed in place and Go does not allow
// taking address of map elements which prevents us from
// assigning a new array for that entry unless we have the
// map available in the context, which is achieved by iterating
// until the element before the last one as opposed to
// Set/Get functions in this file.
beforeLast := i == len(segments)-2
switch current.Type {
case SegmentIndex:
array, ok := in.([]any)
if !ok {
return errors.Errorf("%s is not an array", segments[:i])
}
// It doesn't exist anyway.
if uint(len(array)) <= current.Index {
return nil
}
if beforeLast {
o, err := deleteField(array[current.Index], segments[len(segments)-1])
if err != nil {
return errors.Wrapf(err, "cannot delete %s", segments)
}
array[current.Index] = o
return nil
}
in = array[current.Index]
case SegmentField:
object, ok := in.(map[string]any)
if !ok {
return errors.Errorf("%s is not an object", segments[:i])
}
// It doesn't exist anyway.
if _, ok := object[current.Field]; !ok {
return nil
}
if beforeLast {
o, err := deleteField(object[current.Field], segments[len(segments)-1])
if err != nil {
return errors.Wrapf(err, "cannot delete %s", segments)
}
object[current.Field] = o
return nil
}
in = object[current.Field]
}
}
return nil
}
// deleteField deletes the object in obj pointed by
// the given Segment and returns it. Returned object
// may or may not have the same address in memory.
func deleteField(obj any, s Segment) (any, error) {
switch s.Type {
case SegmentIndex:
array, ok := obj.([]any)
if !ok {
return nil, errors.New("not an array")
}
if len(array) == 0 || uint(len(array)) <= s.Index {
return array, nil
}
for i := s.Index; i < uint(len(array))-1; i++ {
array[i] = array[i+1]
}
return array[:len(array)-1], nil
case SegmentField:
object, ok := obj.(map[string]any)
if !ok {
return nil, errors.New("not an object")
}
delete(object, s.Field)
return object, nil
}
return nil, nil
}

View File

@ -17,14 +17,16 @@ limitations under the License.
package fieldpath
import (
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
"github.com/google/go-cmp/cmp/cmpopts"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/json"
"github.com/crossplane/crossplane-runtime/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
@ -36,12 +38,12 @@ func TestIsNotFound(t *testing.T) {
}{
"NotFound": {
reason: "An error with method `IsNotFound() bool` should be considered a not found error.",
err: errNotFound{errors.New("boom")},
err: notFoundError{errors.New("boom")},
want: true,
},
"WrapsNotFound": {
reason: "An error that wraps an error with method `IsNotFound() bool` should be considered a not found error.",
err: errors.Wrap(errNotFound{errors.New("boom")}, "because reasons"),
err: errors.Wrap(notFoundError{errors.New("boom")}, "because reasons"),
want: true,
},
"SomethingElse": {
@ -63,9 +65,10 @@ func TestIsNotFound(t *testing.T) {
func TestGetValue(t *testing.T) {
type want struct {
value interface{}
value any
err error
}
cases := map[string]struct {
reason string
path string
@ -125,7 +128,7 @@ func TestGetValue(t *testing.T) {
path: "metadata.name",
data: []byte(`{"metadata":{"nope":"cool"}}`),
want: want{
err: errNotFound{errors.New("metadata.name: no such field")},
err: notFoundError{errors.New("metadata.name: no such field")},
},
},
"InsufficientContainers": {
@ -133,7 +136,7 @@ func TestGetValue(t *testing.T) {
path: "spec.containers[1].name",
data: []byte(`{"spec":{"containers":[{"name":"cool"}]}}`),
want: want{
err: errNotFound{errors.New("spec.containers[1]: no such element")},
err: notFoundError{errors.New("spec.containers[1]: no such element")},
},
},
"NotAnArray": {
@ -159,11 +162,19 @@ func TestGetValue(t *testing.T) {
err: errors.Wrap(errors.New("unexpected ']' at position 5"), "cannot parse path \"spec[]\""),
},
},
"NilParent": {
reason: "Request for a path with a nil parent value",
path: "spec.containers[*].name",
data: []byte(`{"spec":{"containers": null}}`),
want: want{
err: notFoundError{errors.Errorf("%s: expected map, got nil", "spec.containers")},
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -171,6 +182,7 @@ func TestGetValue(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetValue(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetValue(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -189,12 +201,14 @@ func TestGetValueInto(t *testing.T) {
type args struct {
path string
out interface{}
out any
}
type want struct {
out interface{}
out any
err error
}
cases := map[string]struct {
reason string
data []byte
@ -232,14 +246,14 @@ func TestGetValueInto(t *testing.T) {
},
want: want{
out: &Struct{},
err: errNotFound{errors.New("s: no such field")},
err: notFoundError{errors.New("s: no such field")},
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -247,6 +261,7 @@ func TestGetValueInto(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetValueInto(%s): %s: -want error, +got error:\n%s", tc.args.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.out, tc.args.out); diff != "" {
t.Errorf("\np.GetValueInto(%s): %s: -want, +got:\n%s", tc.args.path, tc.reason, diff)
}
@ -259,6 +274,7 @@ func TestGetString(t *testing.T) {
value string
err error
}
cases := map[string]struct {
reason string
path string
@ -292,7 +308,7 @@ func TestGetString(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -300,6 +316,7 @@ func TestGetString(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetString(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetString(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -312,6 +329,7 @@ func TestGetStringArray(t *testing.T) {
value []string
err error
}
cases := map[string]struct {
reason string
path string
@ -353,7 +371,7 @@ func TestGetStringArray(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -361,6 +379,7 @@ func TestGetStringArray(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetStringArray(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetStringArray(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -373,6 +392,7 @@ func TestGetStringObject(t *testing.T) {
value map[string]string
err error
}
cases := map[string]struct {
reason string
path string
@ -414,7 +434,7 @@ func TestGetStringObject(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -422,6 +442,7 @@ func TestGetStringObject(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetStringObject(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetStringObject(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -434,6 +455,7 @@ func TestGetBool(t *testing.T) {
value bool
err error
}
cases := map[string]struct {
reason string
path string
@ -467,7 +489,7 @@ func TestGetBool(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -475,6 +497,7 @@ func TestGetBool(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetBool(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetBool(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -482,64 +505,12 @@ func TestGetBool(t *testing.T) {
}
}
func TestGetNumber(t *testing.T) {
type want struct {
value float64
err error
}
cases := map[string]struct {
reason string
path string
data []byte
want want
}{
"MetadataVersion": {
reason: "Requesting a number field should work",
path: "metadata.version",
data: []byte(`{"metadata":{"version":2.0}}`),
want: want{
value: 2,
},
},
"MalformedPath": {
reason: "Requesting an invalid field path should fail",
path: "spec[]",
want: want{
err: errors.Wrap(errors.New("unexpected ']' at position 5"), "cannot parse path \"spec[]\""),
},
},
"NotANumber": {
reason: "Requesting an non-number field path should fail",
path: "metadata.name",
data: []byte(`{"metadata":{"name":"cool"}}`),
want: want{
err: errors.New("metadata.name: not a (float64) number"),
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
got, err := p.GetNumber(tc.path)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetNumber(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetNumber(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
})
}
}
func TestGetInteger(t *testing.T) {
type want struct {
value int64
err error
}
cases := map[string]struct {
reason string
path string
@ -573,7 +544,7 @@ func TestGetInteger(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
@ -581,6 +552,7 @@ func TestGetInteger(t *testing.T) {
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.GetNumber(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.value, got); diff != "" {
t.Errorf("\np.GetNumber(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
@ -591,12 +563,15 @@ func TestGetInteger(t *testing.T) {
func TestSetValue(t *testing.T) {
type args struct {
path string
value interface{}
value any
opts []PavedOption
}
type want struct {
object map[string]interface{}
object map[string]any
err error
}
cases := map[string]struct {
reason string
data []byte
@ -611,8 +586,8 @@ func TestSetValue(t *testing.T) {
value: "cool",
},
want: want{
object: map[string]interface{}{
"metadata": map[string]interface{}{
object: map[string]any{
"metadata": map[string]any{
"name": "cool",
},
},
@ -626,8 +601,8 @@ func TestSetValue(t *testing.T) {
value: "cool",
},
want: want{
object: map[string]interface{}{
"metadata": map[string]interface{}{
object: map[string]any{
"metadata": map[string]any{
"name": "cool",
},
},
@ -641,10 +616,10 @@ func TestSetValue(t *testing.T) {
value: "cool",
},
want: want{
object: map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
object: map[string]any{
"spec": map[string]any{
"containers": []any{
map[string]any{
"name": "cool",
},
},
@ -660,10 +635,10 @@ func TestSetValue(t *testing.T) {
value: "cool",
},
want: want{
object: map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
object: map[string]any{
"spec": map[string]any{
"containers": []any{
map[string]any{
"name": "cool",
},
},
@ -679,13 +654,13 @@ func TestSetValue(t *testing.T) {
value: "cooler",
},
want: want{
object: map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
object: map[string]any{
"spec": map[string]any{
"containers": []any{
map[string]any{
"name": "cool",
},
map[string]interface{}{
map[string]any{
"name": "cooler",
},
},
@ -701,9 +676,9 @@ func TestSetValue(t *testing.T) {
value: "a",
},
want: want{
object: map[string]interface{}{
"data": []interface{}{
[]interface{}{"a"},
object: map[string]any{
"data": []any{
[]any{"a"},
},
},
},
@ -716,9 +691,9 @@ func TestSetValue(t *testing.T) {
value: "b",
},
want: want{
object: map[string]interface{}{
"data": []interface{}{
[]interface{}{"a", "b"},
object: map[string]any{
"data": []any{
[]any{"a", "b"},
},
},
},
@ -731,28 +706,62 @@ func TestSetValue(t *testing.T) {
value: "c",
},
want: want{
object: map[string]interface{}{
"data": []interface{}{"a", nil, "c"},
object: map[string]any{
"data": []any{"a", nil, "c"},
},
},
},
"RejectsHighIndexes": {
reason: "Paths having indexes above the maximum default value are rejected",
data: []byte(`{"data":["a"]}`),
args: args{
path: fmt.Sprintf("data[%v]", DefaultMaxFieldPathIndex+1),
value: "c",
},
want: want{
object: map[string]any{
"data": []any{"a"},
},
err: errors.Errorf("index %v is greater than max allowed index %v",
DefaultMaxFieldPathIndex+1, DefaultMaxFieldPathIndex),
},
},
"NotRejectsHighIndexesIfNoDefaultOptions": {
reason: "Paths having indexes above the maximum default value are not rejected if default disabled",
data: []byte(`{"data":["a"]}`),
args: args{
path: fmt.Sprintf("data[%v]", DefaultMaxFieldPathIndex+1),
value: "c",
opts: []PavedOption{WithMaxFieldPathIndex(0)},
},
want: want{
object: map[string]any{
"data": func() []any {
res := make([]any, DefaultMaxFieldPathIndex+2)
res[0] = "a"
res[DefaultMaxFieldPathIndex+1] = "c"
return res
}(),
},
},
},
"MapStringString": {
reason: "A map of string to string should be converted to a map of string to interface{}",
reason: "A map of string to string should be converted to a map of string to any",
data: []byte(`{"metadata":{}}`),
args: args{
path: "metadata.labels",
value: map[string]string{"cool": "very"},
},
want: want{
object: map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{"cool": "very"},
object: map[string]any{
"metadata": map[string]any{
"labels": map[string]any{"cool": "very"},
},
},
},
},
"OwnerReference": {
reason: "An ObjectReference (i.e. struct) should be converted to a map of string to interface{}",
reason: "An ObjectReference (i.e. struct) should be converted to a map of string to any",
data: []byte(`{"metadata":{}}`),
args: args{
path: "metadata.ownerRefs[0]",
@ -764,10 +773,10 @@ func TestSetValue(t *testing.T) {
},
},
want: want{
object: map[string]interface{}{
"metadata": map[string]interface{}{
"ownerRefs": []interface{}{
map[string]interface{}{
object: map[string]any{
"metadata": map[string]any{
"ownerRefs": []any{
map[string]any{
"apiVersion": "v",
"kind": "k",
"name": "n",
@ -785,7 +794,7 @@ func TestSetValue(t *testing.T) {
path: "data[0]",
},
want: want{
object: map[string]interface{}{"data": map[string]interface{}{}},
object: map[string]any{"data": map[string]any{}},
err: errors.New("data is not an array"),
},
},
@ -796,7 +805,7 @@ func TestSetValue(t *testing.T) {
path: "data.name",
},
want: want{
object: map[string]interface{}{"data": []interface{}{}},
object: map[string]any{"data": []any{}},
err: errors.New("data is not an object"),
},
},
@ -806,7 +815,7 @@ func TestSetValue(t *testing.T) {
path: "spec[]",
},
want: want{
object: map[string]interface{}{},
object: map[string]any{},
err: errors.Wrap(errors.New("unexpected ']' at position 5"), "cannot parse path \"spec[]\""),
},
},
@ -814,17 +823,476 @@ func TestSetValue(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]interface{})
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
p := Pave(in, tc.args.opts...)
err := p.SetValue(tc.args.path, tc.args.value)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.SetValue(%s, %v): %s: -want error, +got error:\n%s", tc.args.path, tc.args.value, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.object, p.object); diff != "" {
t.Fatalf("\np.SetValue(%s, %v): %s: -want, +got:\n%s", tc.args.path, tc.args.value, tc.reason, diff)
}
})
}
}
func TestExpandWildcards(t *testing.T) {
type want struct {
expanded []string
err error
}
cases := map[string]struct {
reason string
path string
data []byte
want want
}{
"NoWildcardExisting": {
reason: "It should return same path if no wildcard in an existing path",
path: "password",
data: []byte(`{"password":"top-secret"}`),
want: want{
expanded: []string{"password"},
},
},
"NoWildcardNonExisting": {
reason: "It should return no results if no wildcard in a non-existing path",
path: "username",
data: []byte(`{"password":"top-secret"}`),
want: want{
expanded: []string{},
},
},
"NestedNoWildcardExisting": {
reason: "It should return same path if no wildcard in an existing path",
path: "items[0][1]",
data: []byte(`{"items":[["a", "b"]]}`),
want: want{
expanded: []string{"items[0][1]"},
},
},
"NestedNoWildcardNonExisting": {
reason: "It should return no results if no wildcard in a non-existing path",
path: "items[0][5]",
data: []byte(`{"items":[["a", "b"]]}`),
want: want{
expanded: []string{},
},
},
"NestedArray": {
reason: "It should return all possible paths for an array",
path: "items[*][*]",
data: []byte(`{"items":[["a", "b", "c"], ["d"]]}`),
want: want{
expanded: []string{"items[0][0]", "items[0][1]", "items[0][2]", "items[1][0]"},
},
},
"KeysOfMap": {
reason: "It should return all possible paths for a map in proper syntax",
path: "items[*]",
data: []byte(`{"items":{ "key1": "val1", "key2.as.annotation": "val2"}}`),
want: want{
expanded: []string{"items.key1", "items[key2.as.annotation]"},
},
},
"ArrayOfObjects": {
reason: "It should return all possible paths for an array of objects",
path: "spec.containers[*][*]",
data: []byte(`{"spec":{"containers":[{"name":"cool", "image": "latest", "args": ["start", "now"]}]}}`),
want: want{
expanded: []string{"spec.containers[0].name", "spec.containers[0].image", "spec.containers[0].args"},
},
},
"MultiLayer": {
reason: "It should return all possible paths for a multilayer input",
path: "spec.containers[*].args[*]",
data: []byte(`{"spec":{"containers":[{"name":"cool", "image": "latest", "args": ["start", "now", "debug"]}]}}`),
want: want{
expanded: []string{"spec.containers[0].args[0]", "spec.containers[0].args[1]", "spec.containers[0].args[2]"},
},
},
"WildcardInTheBeginning": {
reason: "It should return all possible paths for a multilayer input with wildcard in the beginning",
path: "spec.containers[*].args[1]",
data: []byte(`{"spec":{"containers":[{"name":"cool", "image": "latest", "args": ["start", "now", "debug"]}]}}`),
want: want{
expanded: []string{"spec.containers[0].args[1]"},
},
},
"WildcardAtTheEnd": {
reason: "It should return all possible paths for a multilayer input with wildcard at the end",
path: "spec.containers[0].args[*]",
data: []byte(`{"spec":{"containers":[{"name":"cool", "image": "latest", "args": ["start", "now", "debug"]}]}}`),
want: want{
expanded: []string{"spec.containers[0].args[0]", "spec.containers[0].args[1]", "spec.containers[0].args[2]"},
},
},
"NoData": {
reason: "If there is no input data, no expanded fields could be found",
path: "metadata[*]",
data: nil,
want: want{
expanded: []string{},
},
},
"InsufficientContainers": {
reason: "Requesting a non-existent array element should return nothing",
path: "spec.containers[1].args[*]",
data: []byte(`{"spec":{"containers":[{"name":"cool"}]}}`),
want: want{
expanded: []string{},
},
},
"UnexpectedWildcard": {
reason: "Requesting a wildcard for an object should fail",
path: "spec.containers[0].name[*]",
data: []byte(`{"spec":{"containers":[{"name":"cool"}]}}`),
want: want{
err: errors.Wrapf(errors.Errorf("%q: unexpected wildcard usage", "spec.containers[0].name"), "cannot expand wildcards for segments: %q", "spec.containers[0].name[*]"),
},
},
"NotAnArray": {
reason: "Indexing an object should fail",
path: "metadata[1]",
data: []byte(`{"metadata":{"nope":"cool"}}`),
want: want{
err: errors.Wrapf(errors.New("metadata: not an array"), "cannot expand wildcards for segments: %q", "metadata[1]"),
},
},
"NotAnObject": {
reason: "Requesting a field in an array should fail",
path: "spec.containers[nope].name",
data: []byte(`{"spec":{"containers":[{"name":"cool"}]}}`),
want: want{
err: errors.Wrapf(errors.New("spec.containers: not an object"), "cannot expand wildcards for segments: %q", "spec.containers.nope.name"),
},
},
"MalformedPath": {
reason: "Requesting an invalid field path should fail",
path: "spec[]",
want: want{
err: errors.Wrap(errors.New("unexpected ']' at position 5"), "cannot parse path \"spec[]\""),
},
},
"NilValue": {
reason: "Requesting a wildcard for an object that has nil value",
path: "spec.containers[*].name",
data: []byte(`{"spec":{"containers": null}}`),
want: want{
err: errors.Wrapf(notFoundError{errors.Errorf("wildcard field %q is not found in the path", "spec.containers")}, "cannot expand wildcards for segments: %q", "spec.containers[*].name"),
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
got, err := p.ExpandWildcards(tc.path)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.ExpandWildcards(%s): %s: -want error, +got error:\n%s", tc.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.expanded, got, cmpopts.SortSlices(func(x, y string) bool {
return x < y
})); diff != "" {
t.Errorf("\np.ExpandWildcards(%s): %s: -want, +got:\n%s", tc.path, tc.reason, diff)
}
})
}
}
func TestDeleteField(t *testing.T) {
type args struct {
path string
}
type want struct {
object map[string]any
err error
}
cases := map[string]struct {
reason string
data []byte
args args
want want
}{
"MalformedPath": {
reason: "Requesting an invalid field path should fail",
args: args{
path: "spec[]",
},
want: want{
object: map[string]any{},
err: errors.Wrap(errors.New("unexpected ']' at position 5"), "cannot parse path \"spec[]\""),
},
},
"IndexGivenForNonArray": {
reason: "Trying to delete a numbered index from a map should fail.",
data: []byte(`{"data":{}}`),
args: args{
path: "data[0]",
},
want: want{
object: map[string]any{"data": map[string]any{}},
err: errors.Wrap(errors.New("not an array"), "cannot delete data[0]"),
},
},
"KeyGivenForNonMap": {
reason: "Trying to delete a key from an array should fail.",
data: []byte(`{"data":[["a"]]}`),
args: args{
path: "data[0].a",
},
want: want{
object: map[string]any{"data": []any{[]any{"a"}}},
err: errors.Wrap(errors.New("not an object"), "cannot delete data[0].a"),
},
},
"KeyGivenForNonMapInMiddle": {
reason: "If one of the segments that is a field corresponds to array, it should fail.",
data: []byte(`{"data":[{"another": "field"}]}`),
args: args{
path: "data.some.another",
},
want: want{
object: map[string]any{"data": []any{
map[string]any{
"another": "field",
},
}},
err: errors.New("data is not an object"),
},
},
"IndexGivenForNonArrayInMiddle": {
reason: "If one of the segments that is an index corresponds to map, it should fail.",
data: []byte(`{"data":{"another": ["field"]}}`),
args: args{
path: "data[0].another",
},
want: want{
object: map[string]any{"data": map[string]any{
"another": []any{
"field",
},
}},
err: errors.New("data is not an array"),
},
},
"ObjectField": {
reason: "Deleting a field from a map should work.",
data: []byte(`{"metadata":{"name":"lame"}}`),
args: args{
path: "metadata.name",
},
want: want{
object: map[string]any{
"metadata": map[string]any{},
},
},
},
"ObjectSingleField": {
reason: "Deleting a field from a map should work.",
data: []byte(`{"metadata":{"name":"lame"}, "olala": {"omama": "koala"}}`),
args: args{
path: "metadata",
},
want: want{
object: map[string]any{
"olala": map[string]any{
"omama": "koala",
},
},
},
},
"ObjectLeafField": {
reason: "Deleting a field that is deep in the tree from a map should work.",
data: []byte(`{"spec":{"some": {"more": "delete-me"}}}`),
args: args{
path: "spec.some.more",
},
want: want{
object: map[string]any{
"spec": map[string]any{
"some": map[string]any{},
},
},
},
},
"ObjectMidField": {
reason: "Deleting a field that is in the middle of the tree from a map should work.",
data: []byte(`{"spec":{"some": {"more": "delete-me"}}}`),
args: args{
path: "spec.some",
},
want: want{
object: map[string]any{
"spec": map[string]any{},
},
},
},
"ObjectInArray": {
reason: "Deleting a field that is in the middle of the tree from a map should work.",
data: []byte(`{"spec":[{"some": {"more": "delete-me"}}]}`),
args: args{
path: "spec[0].some.more",
},
want: want{
object: map[string]any{
"spec": []any{
map[string]any{
"some": map[string]any{},
},
},
},
},
},
"ArrayFirstElement": {
reason: "Deleting the first element from an array should work",
data: []byte(`{"items":["a", "b"]}`),
args: args{
path: "items[0]",
},
want: want{
object: map[string]any{
"items": []any{
"b",
},
},
},
},
"ArrayLastElement": {
reason: "Deleting the last element from an array should work",
data: []byte(`{"items":["a", "b"]}`),
args: args{
path: "items[1]",
},
want: want{
object: map[string]any{
"items": []any{
"a",
},
},
},
},
"ArrayMidElement": {
reason: "Deleting an element that is neither first nor last from an array should work",
data: []byte(`{"items":["a", "b", "c"]}`),
args: args{
path: "items[1]",
},
want: want{
object: map[string]any{
"items": []any{
"a",
"c",
},
},
},
},
"ArrayOnlyElements": {
reason: "Deleting the only element from an array should work",
data: []byte(`{"items":["a"]}`),
args: args{
path: "items[0]",
},
want: want{
object: map[string]any{
"items": []any{},
},
},
},
"ArrayMultipleIndex": {
reason: "Deleting an element from an array of array should work",
data: []byte(`{"items":[["a", "b"]]}`),
args: args{
path: "items[0][1]",
},
want: want{
object: map[string]any{
"items": []any{
[]any{
"a",
},
},
},
},
},
"ArrayNoElement": {
reason: "Deleting an element from an empty array should work",
data: []byte(`{"items":[]}`),
args: args{
path: "items[0]",
},
want: want{
object: map[string]any{
"items": []any{},
},
},
},
"NonExistentPathInMap": {
reason: "It should be no-op if the field does not exist already.",
data: []byte(`{"items":[]}`),
args: args{
path: "items[0].metadata",
},
want: want{
object: map[string]any{
"items": []any{},
},
},
},
"NonExistentPathInArray": {
reason: "It should be no-op if the field does not exist already.",
data: []byte(`{"items":{"some": "other"}}`),
args: args{
path: "items.metadata[0]",
},
want: want{
object: map[string]any{
"items": map[string]any{
"some": "other",
},
},
},
},
"NonExistentElementInArray": {
reason: "It should be no-op if the field does not exist already.",
data: []byte(`{"items":["some", "other"]}`),
args: args{
path: "items[5]",
},
want: want{
object: map[string]any{
"items": []any{
"some", "other",
},
},
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
in := make(map[string]any)
_ = json.Unmarshal(tc.data, &in)
p := Pave(in)
err := p.DeleteField(tc.args.path)
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Fatalf("\np.DeleteField(%s): %s: -want error, +got error:\n%s", tc.args.path, tc.reason, diff)
}
if diff := cmp.Diff(tc.want.object, p.object); diff != "" {
t.Fatalf("\np.DeleteField(%s): %s: -want, +got:\n%s", tc.args.path, tc.reason, diff)
}
})
}
}

106
pkg/gate/gate.go Normal file
View File

@ -0,0 +1,106 @@
/*
Copyright 2025 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 gate contains a gated function callback registration implementation.
package gate
import (
"slices"
"sync"
)
// Gate implements a gated function callback registration with comparable conditions.
type Gate[T comparable] struct {
mux sync.RWMutex
satisfied map[T]bool
fns []gated[T]
}
// gated is an internal tracking resource.
type gated[T comparable] struct {
// fn is the function callback we will invoke when all the dependent conditions are true.
fn func()
// depends is the list of conditions this gated function is waiting on. This is an AND.
depends []T
// released means the gated function has been invoked and we can garbage collect this gated function.
released bool
}
// Register a callback function that will be called when all the provided dependent conditions are true.
// After all conditions are true, the callback function is removed from the registration and will not be called again.
// Thread Safe.
func (g *Gate[T]) Register(fn func(), depends ...T) {
g.mux.Lock()
g.fns = append(g.fns, gated[T]{fn: fn, depends: depends})
g.mux.Unlock()
g.process()
}
// Set marks the associated condition to the given value. If the condition is already set as that value, then this is a
// no-op. Returns true if there was an update detected. Thread safe.
func (g *Gate[T]) Set(condition T, value bool) bool {
g.mux.Lock()
if g.satisfied == nil {
g.satisfied = make(map[T]bool)
}
old, found := g.satisfied[condition]
updated := false
if !found || old != value {
updated = true
g.satisfied[condition] = value
}
// process() would also like to lock the mux, so we must unlock here directly and not use defer.
g.mux.Unlock()
if updated {
g.process()
}
return updated
}
func (g *Gate[T]) process() {
g.mux.Lock()
defer g.mux.Unlock()
for i := range g.fns {
// release controls if we should release the function.
release := true
for _, dep := range g.fns[i].depends {
if !g.satisfied[dep] {
release = false
}
}
if release {
fn := g.fns[i].fn
// mark the function released so we can garbage collect after we are done with the loop.
g.fns[i].released = true
// Need to capture a copy of fn or else we would be accessing a deleted member when the go routine runs.
go fn()
}
}
// garbage collect released functions.
g.fns = slices.DeleteFunc(g.fns, func(a gated[T]) bool {
return a.released
})
}

299
pkg/gate/gate_test.go Normal file
View File

@ -0,0 +1,299 @@
/*
Copyright 2025 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 gate_test
import (
"sync"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/crossplane/crossplane-runtime/pkg/gate"
)
func TestGateRegister(t *testing.T) {
type args struct {
depends []string
}
type want struct {
called bool
}
cases := map[string]struct {
reason string
args args
want want
}{
"NoDependencies": {
reason: "Should immediately call function when no dependencies are required",
args: args{
depends: []string{},
},
want: want{
called: true,
},
},
"SingleDependency": {
reason: "Should not call function when dependency is not met",
args: args{
depends: []string{"condition1"},
},
want: want{
called: false,
},
},
"MultipleDependencies": {
reason: "Should not call function when multiple dependencies are not met",
args: args{
depends: []string{"condition1", "condition2"},
},
want: want{
called: false,
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
g := new(gate.Gate[string])
called := false
g.Register(func() {
called = true
}, tc.args.depends...)
// Give some time for goroutine to execute
time.Sleep(10 * time.Millisecond)
if diff := cmp.Diff(tc.want.called, called); diff != "" {
t.Errorf("\n%s\nRegister(...): -want called, +got called:\n%s", tc.reason, diff)
}
})
}
}
func TestGateIntegration(t *testing.T) {
type want struct {
called bool
}
cases := map[string]struct {
reason string
setup func(g *gate.Gate[string]) chan bool
want want
}{
"SingleDependencyMet": {
reason: "Should call function when single dependency is met",
setup: func(g *gate.Gate[string]) chan bool {
called := make(chan bool, 1)
g.Register(func() {
called <- true
}, "condition1")
// Set condition to true (will be initialized as false first)
g.Set("condition1", true)
return called
},
want: want{
called: true,
},
},
"MultipleDependenciesMet": {
reason: "Should call function when all dependencies are met",
setup: func(g *gate.Gate[string]) chan bool {
called := make(chan bool, 1)
g.Register(func() {
called <- true
}, "condition1", "condition2")
// Set both conditions to true
g.Set("condition1", true)
g.Set("condition2", true)
return called
},
want: want{
called: true,
},
},
"PartialDependenciesMet": {
reason: "Should not call function when only some dependencies are met",
setup: func(g *gate.Gate[string]) chan bool {
called := make(chan bool, 1)
g.Register(func() {
called <- true
}, "condition1", "condition2")
// Set only one condition to true
g.Set("condition1", true)
return called
},
want: want{
called: false,
},
},
"DependenciesAlreadyMet": {
reason: "Should call function when dependencies are already met",
setup: func(g *gate.Gate[string]) chan bool {
called := make(chan bool, 1)
g.Set("condition1", true)
g.Set("condition2", true)
g.Register(func() {
called <- true
}, "condition1", "condition2")
return called
},
want: want{
called: true,
},
},
"DependencySetThenUnset": {
reason: "Should call function when dependency is met, even if unset later",
setup: func(g *gate.Gate[string]) chan bool {
called := make(chan bool, 1)
g.Register(func() {
called <- true
}, "condition1")
// Set condition to true then false (function already called when true)
g.Set("condition1", true)
g.Set("condition1", false)
return called
},
want: want{
called: true,
},
},
"FunctionCalledOnlyOnce": {
reason: "Should call function only once even if conditions change after",
setup: func(g *gate.Gate[string]) chan bool {
called := make(chan bool, 2) // Buffer for potential multiple calls
g.Register(func() {
called <- true
}, "condition1")
// Set condition multiple times
g.Set("condition1", true)
g.Set("condition1", false)
g.Set("condition1", true)
return called
},
want: want{
called: true,
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
g := new(gate.Gate[string])
callChannel := tc.setup(g)
var got bool
select {
case got = <-callChannel:
case <-time.After(100 * time.Millisecond):
got = false
}
if diff := cmp.Diff(tc.want.called, got); diff != "" {
t.Errorf("\n%s\nIntegration test: -want called, +got called:\n%s", tc.reason, diff)
}
// For the "only once" test, ensure no additional calls
if name == "FunctionCalledOnlyOnce" && tc.want.called {
select {
case <-callChannel:
t.Errorf("\n%s\nFunction was called more than once", tc.reason)
case <-time.After(50 * time.Millisecond):
// Good - no additional calls
}
}
})
}
}
func TestGateConcurrency(t *testing.T) {
g := new(gate.Gate[string])
const numGoroutines = 100
var wg sync.WaitGroup
callCount := make(chan struct{}, numGoroutines)
// Register functions concurrently
for range numGoroutines {
wg.Add(1)
go func() {
defer wg.Done()
g.Register(func() {
callCount <- struct{}{}
}, "shared-condition")
}()
}
// Wait for all registrations
wg.Wait()
// Set condition to true once
g.Set("shared-condition", true)
// Give some time for goroutines to execute
time.Sleep(100 * time.Millisecond)
// Count how many functions were called
close(callCount)
count := 0
for range callCount {
count++
}
if count != numGoroutines {
t.Errorf("Expected %d function calls, got %d", numGoroutines, count)
}
}
func TestGateTypeSafety(t *testing.T) {
intGate := new(gate.Gate[int])
called := false
intGate.Register(func() {
called = true
}, 1, 2, 3)
intGate.Set(1, true)
intGate.Set(2, true)
intGate.Set(3, true)
// Give some time for goroutine to execute
time.Sleep(10 * time.Millisecond)
if !called {
t.Error("Function should have been called when all int conditions were met")
}
}

62
pkg/logging/klog.go Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2024 Upbound Inc.
// All rights reserved
package logging
import (
"flag"
"os"
"strings"
"github.com/go-logr/logr"
"k8s.io/klog/v2"
)
// SetFilteredKlogLogger sets log as the logger backend of klog, but filtering
// aggressively to avoid noise.
func SetFilteredKlogLogger(log logr.Logger) {
// initialize klog at verbosity level 3, dropping everything higher.
fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
klog.InitFlags(fs)
fs.Parse([]string{"--v=3"}) //nolint:errcheck // we couldn't do anything here anyway
klogr := logr.New(&requestThrottlingFilter{log.GetSink()})
klog.SetLogger(klogr)
}
// requestThrottlingFilter drops everything that is not a client-go throttling
// message, compare:
// https://github.com/kubernetes/client-go/blob/8c4efe8d079e405329f314fb789a41ac6af101dc/rest/request.go#L621
type requestThrottlingFilter struct {
logr.LogSink
}
func (l *requestThrottlingFilter) Info(level int, msg string, keysAndValues ...interface{}) {
if !strings.Contains(msg, "Waited for ") || !strings.Contains(msg, " request: ") {
return
}
l.LogSink.Info(l.klogToLogrLevel(level), msg, keysAndValues...)
}
func (l *requestThrottlingFilter) Enabled(level int) bool {
return l.LogSink.Enabled(l.klogToLogrLevel(level))
}
func (l *requestThrottlingFilter) klogToLogrLevel(klogLvl int) int {
// we want a default klog level of 3 for info, 4 for debug, corresponding to
// logr levels of 0 and 1.
if klogLvl >= 3 {
return klogLvl - 3
}
return 0
}
func (l *requestThrottlingFilter) WithCallDepth(depth int) logr.LogSink {
if delegate, ok := l.LogSink.(logr.CallDepthLogSink); ok {
return &requestThrottlingFilter{LogSink: delegate.WithCallDepth(depth)}
}
return l
}

View File

@ -46,19 +46,19 @@ type Logger interface {
// be supplied as an array that alternates between string keys and values of
// an arbitrary type. Use Info for messages that Crossplane operators are
// very likely to be concerned with when running Crossplane.
Info(msg string, keysAndValues ...interface{})
Info(msg string, keysAndValues ...any)
// Debug logs a message with optional structured data. Structured data must
// be supplied as an array that alternates between string keys and values of
// an arbitrary type. Use Debug for messages that Crossplane operators or
// developers may be concerned with when debugging Crossplane.
Debug(msg string, keysAndValues ...interface{})
Debug(msg string, keysAndValues ...any)
// WithValues returns a Logger that will include the supplied structured
// data with any subsequent messages it logs. Structured data must
// be supplied as an array that alternates between string keys and values of
// an arbitrary type.
WithValues(keysAndValues ...interface{}) Logger
WithValues(keysAndValues ...any) Logger
}
// NewNopLogger returns a Logger that does nothing.
@ -66,9 +66,9 @@ func NewNopLogger() Logger { return nopLogger{} }
type nopLogger struct{}
func (l nopLogger) Info(msg string, keysAndValues ...interface{}) {}
func (l nopLogger) Debug(msg string, keysAndValues ...interface{}) {}
func (l nopLogger) WithValues(keysAndValues ...interface{}) Logger { return nopLogger{} }
func (l nopLogger) Info(_ string, _ ...any) {}
func (l nopLogger) Debug(_ string, _ ...any) {}
func (l nopLogger) WithValues(_ ...any) Logger { return nopLogger{} }
// NewLogrLogger returns a Logger that is satisfied by the supplied logr.Logger,
// which may be satisfied in turn by various logging implementations (Zap, klog,
@ -81,14 +81,14 @@ type logrLogger struct {
log logr.Logger
}
func (l logrLogger) Info(msg string, keysAndValues ...interface{}) {
l.log.Info(msg, keysAndValues...)
func (l logrLogger) Info(msg string, keysAndValues ...any) {
l.log.Info(msg, keysAndValues...) //nolint:logrlint // False positive - logrlint thinks there's an odd number of args.
}
func (l logrLogger) Debug(msg string, keysAndValues ...interface{}) {
l.log.V(1).Info(msg, keysAndValues...)
func (l logrLogger) Debug(msg string, keysAndValues ...any) {
l.log.V(1).Info(msg, keysAndValues...) //nolint:logrlint // False positive - logrlint thinks there's an odd number of args.
}
func (l logrLogger) WithValues(keysAndValues ...interface{}) Logger {
return logrLogger{log: l.log.WithValues(keysAndValues...)}
func (l logrLogger) WithValues(keysAndValues ...any) Logger {
return logrLogger{log: l.log.WithValues(keysAndValues...)} //nolint:logrlint // False positive - logrlint thinks there's an odd number of args.
}

View File

@ -18,32 +18,49 @@ limitations under the License.
package meta
import (
"fmt"
"hash/fnv"
"strings"
"time"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
// AnnotationKeyExternalName is the key in the annotations map of a resource for
// the name of the resource as it appears on provider's systems.
const AnnotationKeyExternalName = "crossplane.io/external-name"
// Supported resources with all of these annotations will be fully or partially
// propagated to the named resource of the same kind, assuming it exists and
// consents to propagation.
const (
AnnotationKeyPropagateToPrefix = "to.propagate.crossplane.io/"
// AnnotationKeyExternalName is the key in the annotations map of a
// resource for the name of the resource as it appears on provider's
// systems.
AnnotationKeyExternalName = "crossplane.io/external-name"
// Deprecated: This functionality will be removed soon.
AnnotationKeyPropagateFromNamespace = "from.propagate.crossplane.io/namespace"
AnnotationKeyPropagateFromName = "from.propagate.crossplane.io/name"
// AnnotationKeyExternalCreatePending is the key in the annotations map
// of a resource that indicates the last time creation of the external
// resource was pending (i.e. about to happen). Its value must be an
// RFC3999 timestamp.
AnnotationKeyExternalCreatePending = "crossplane.io/external-create-pending"
// AnnotationKeyExternalCreateSucceeded is the key in the annotations
// map of a resource that represents the last time the external resource
// was created successfully. Its value must be an RFC3339 timestamp,
// which can be used to determine how long ago a resource was created.
// This is useful for eventually consistent APIs that may take some time
// before the API called by Observe will report that a recently created
// external resource exists.
AnnotationKeyExternalCreateSucceeded = "crossplane.io/external-create-succeeded"
// AnnotationKeyExternalCreateFailed is the key in the annotations map
// of a resource that indicates the last time creation of the external
// resource failed. Its value must be an RFC3999 timestamp.
AnnotationKeyExternalCreateFailed = "crossplane.io/external-create-failed"
// AnnotationKeyReconciliationPaused is the key in the annotations map
// of a resource that indicates that further reconciliations on the
// resource are paused. All create/update/delete/generic events on
// the resource will be filtered and thus no further reconcile requests
// will be queued for the resource.
AnnotationKeyReconciliationPaused = "crossplane.io/paused"
)
// ReferenceTo returns an object reference to the supplied object, presumed to
@ -53,6 +70,7 @@ const (
// See https://github.com/crossplane/crossplane-runtime/issues/49
func ReferenceTo(o metav1.Object, of schema.GroupVersionKind) *corev1.ObjectReference {
v, k := of.ToAPIVersionAndKind()
return &corev1.ObjectReference{
APIVersion: v,
Kind: k,
@ -66,6 +84,7 @@ func ReferenceTo(o metav1.Object, of schema.GroupVersionKind) *corev1.ObjectRefe
// presumed to be of the supplied group, version, and kind.
func TypedReferenceTo(o metav1.Object, of schema.GroupVersionKind) *xpv1.TypedReference {
v, k := of.ToAPIVersionAndKind()
return &xpv1.TypedReference{
APIVersion: v,
Kind: k,
@ -87,9 +106,11 @@ func AsOwner(r *xpv1.TypedReference) metav1.OwnerReference {
// AsController converts the supplied object reference to a controller
// reference. You may also consider using metav1.NewControllerRef.
func AsController(r *xpv1.TypedReference) metav1.OwnerReference {
c := true
t := true
ref := AsOwner(r)
ref.Controller = &c
ref.Controller = &t
ref.BlockOwnerDeletion = &t
return ref
}
@ -121,9 +142,11 @@ func AddOwnerReference(o metav1.Object, r metav1.OwnerReference) {
if refs[i].UID == r.UID {
refs[i] = r
o.SetOwnerReferences(refs)
return
}
}
o.SetOwnerReferences(append(refs, r))
}
@ -136,6 +159,7 @@ func AddControllerReference(o metav1.Object, r metav1.OwnerReference) error {
}
AddOwnerReference(o, r)
return nil
}
@ -147,6 +171,7 @@ func AddFinalizer(o metav1.Object, finalizer string) {
return
}
}
o.SetFinalizers(append(f, finalizer))
}
@ -158,6 +183,7 @@ func RemoveFinalizer(o metav1.Object, finalizer string) {
f = append(f[:i], f[i+1:]...)
}
}
o.SetFinalizers(f)
}
@ -169,6 +195,7 @@ func FinalizerExists(o metav1.Object, finalizer string) bool {
return true
}
}
return false
}
@ -179,9 +206,11 @@ func AddLabels(o metav1.Object, labels map[string]string) {
o.SetLabels(labels)
return
}
for k, v := range labels {
l[k] = v
}
o.SetLabels(l)
}
@ -191,9 +220,11 @@ func RemoveLabels(o metav1.Object, labels ...string) {
if l == nil {
return
}
for _, k := range labels {
delete(l, k)
}
o.SetLabels(l)
}
@ -204,9 +235,11 @@ func AddAnnotations(o metav1.Object, annotations map[string]string) {
o.SetAnnotations(annotations)
return
}
for k, v := range annotations {
a[k] = v
}
o.SetAnnotations(a)
}
@ -216,9 +249,11 @@ func RemoveAnnotations(o metav1.Object, annotations ...string) {
if a == nil {
return
}
for _, k := range annotations {
delete(a, k)
}
o.SetAnnotations(a)
}
@ -245,62 +280,99 @@ func SetExternalName(o metav1.Object, name string) {
AddAnnotations(o, map[string]string{AnnotationKeyExternalName: name})
}
// AllowPropagation from one object to another by adding consenting annotations
// to both.
// Deprecated: This functionality will be removed soon.
func AllowPropagation(from, to metav1.Object) {
AddAnnotations(to, map[string]string{
AnnotationKeyPropagateFromNamespace: from.GetNamespace(),
AnnotationKeyPropagateFromName: from.GetName(),
})
// GetExternalCreatePending returns the time at which the external resource
// was most recently pending creation.
func GetExternalCreatePending(o metav1.Object) time.Time {
a := o.GetAnnotations()[AnnotationKeyExternalCreatePending]
AddAnnotations(from, map[string]string{
AnnotationKeyPropagateTo(to): to.GetNamespace() + "/" + to.GetName(),
})
}
// AnnotationKeyPropagateTo returns an annotation key whose presence indicates
// that the annotated object consents to propagation from the supplied object.
// The annotation name (which follows the prefix) can be anything that doesn't
// collide with another annotation. to.propagation.crossplane.io/example would
// be valid. This function uses a hash of the supplied object's namespace and
// name in order to avoid collisions and keep the suffix relatively short.
func AnnotationKeyPropagateTo(o metav1.Object) string {
// Writing to a hash never returns an error.
h := fnv.New32a()
h.Write([]byte(o.GetNamespace())) // nolint:errcheck
h.Write([]byte(o.GetName())) // nolint:errcheck
return fmt.Sprintf("%s%x", AnnotationKeyPropagateToPrefix, h.Sum32())
}
// AllowsPropagationFrom returns the NamespacedName of the object the supplied
// object should be propagated from.
func AllowsPropagationFrom(to metav1.Object) types.NamespacedName {
return types.NamespacedName{
Namespace: to.GetAnnotations()[AnnotationKeyPropagateFromNamespace],
Name: to.GetAnnotations()[AnnotationKeyPropagateFromName],
}
}
// AllowsPropagationTo returns the set of NamespacedNames that the supplied
// object may be propagated to.
func AllowsPropagationTo(from metav1.Object) map[types.NamespacedName]bool {
to := make(map[types.NamespacedName]bool)
for k, v := range from.GetAnnotations() {
nn := strings.Split(v, "/")
switch {
case !strings.HasPrefix(k, AnnotationKeyPropagateToPrefix):
continue
case len(nn) != 2:
continue
case nn[0] == "":
continue
case nn[1] == "":
continue
}
to[types.NamespacedName{Namespace: nn[0], Name: nn[1]}] = true
t, err := time.Parse(time.RFC3339, a)
if err != nil {
return time.Time{}
}
return to
return t
}
// SetExternalCreatePending sets the time at which the external resource was
// most recently pending creation to the supplied time.
func SetExternalCreatePending(o metav1.Object, t time.Time) {
AddAnnotations(o, map[string]string{AnnotationKeyExternalCreatePending: t.Format(time.RFC3339)})
}
// GetExternalCreateSucceeded returns the time at which the external resource
// was most recently created.
func GetExternalCreateSucceeded(o metav1.Object) time.Time {
a := o.GetAnnotations()[AnnotationKeyExternalCreateSucceeded]
t, err := time.Parse(time.RFC3339, a)
if err != nil {
return time.Time{}
}
return t
}
// SetExternalCreateSucceeded sets the time at which the external resource was
// most recently created to the supplied time.
func SetExternalCreateSucceeded(o metav1.Object, t time.Time) {
AddAnnotations(o, map[string]string{AnnotationKeyExternalCreateSucceeded: t.Format(time.RFC3339)})
}
// GetExternalCreateFailed returns the time at which the external resource
// recently failed to create.
func GetExternalCreateFailed(o metav1.Object) time.Time {
a := o.GetAnnotations()[AnnotationKeyExternalCreateFailed]
t, err := time.Parse(time.RFC3339, a)
if err != nil {
return time.Time{}
}
return t
}
// SetExternalCreateFailed sets the time at which the external resource most
// recently failed to create.
func SetExternalCreateFailed(o metav1.Object, t time.Time) {
AddAnnotations(o, map[string]string{AnnotationKeyExternalCreateFailed: t.Format(time.RFC3339)})
}
// ExternalCreateIncomplete returns true if creation of the external resource
// appears to be incomplete. We deem creation to be incomplete if the 'external
// create pending' annotation is the newest of all tracking annotations that are
// set (i.e. pending, succeeded, and failed).
func ExternalCreateIncomplete(o metav1.Object) bool {
pending := GetExternalCreatePending(o)
succeeded := GetExternalCreateSucceeded(o)
failed := GetExternalCreateFailed(o)
// If creation never started it can't be incomplete.
if pending.IsZero() {
return false
}
latest := succeeded
if failed.After(succeeded) {
latest = failed
}
return pending.After(latest)
}
// ExternalCreateSucceededDuring returns true if creation of the external
// resource that corresponds to the supplied managed resource succeeded within
// the supplied duration.
func ExternalCreateSucceededDuring(o metav1.Object, d time.Duration) bool {
t := GetExternalCreateSucceeded(o)
if t.IsZero() {
return false
}
return time.Since(t) < d
}
// IsPaused returns true if the object has the AnnotationKeyReconciliationPaused
// annotation set to `true`.
func IsPaused(o metav1.Object) bool {
return o.GetAnnotations()[AnnotationKeyReconciliationPaused] == "true"
}

View File

@ -17,18 +17,17 @@ limitations under the License.
package meta
import (
"fmt"
"hash/fnv"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/crossplane-runtime/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
@ -47,6 +46,7 @@ func TestReferenceTo(t *testing.T) {
o metav1.Object
of schema.GroupVersionKind
}
tests := map[string]struct {
args
want *corev1.ObjectReference
@ -78,7 +78,7 @@ func TestReferenceTo(t *testing.T) {
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := ReferenceTo(tc.args.o, tc.args.of)
got := ReferenceTo(tc.o, tc.of)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("ReferenceTo(): -want, +got:\n%s", diff)
}
@ -91,6 +91,7 @@ func TestTypedReferenceTo(t *testing.T) {
o metav1.Object
of schema.GroupVersionKind
}
tests := map[string]struct {
args
want *xpv1.TypedReference
@ -121,7 +122,7 @@ func TestTypedReferenceTo(t *testing.T) {
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := TypedReferenceTo(tc.args.o, tc.args.of)
got := TypedReferenceTo(tc.o, tc.of)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("TypedReferenceTo(): -want, +got:\n%s", diff)
}
@ -161,7 +162,7 @@ func TestAsOwner(t *testing.T) {
}
func TestAsController(t *testing.T) {
controller := true
flag := true
tests := map[string]struct {
r *xpv1.TypedReference
@ -175,11 +176,12 @@ func TestAsController(t *testing.T) {
UID: uid,
},
want: metav1.OwnerReference{
APIVersion: groupVersion,
Kind: kind,
Name: name,
UID: uid,
Controller: &controller,
APIVersion: groupVersion,
Kind: kind,
Name: name,
UID: uid,
Controller: &flag,
BlockOwnerDeletion: &flag,
},
},
}
@ -825,6 +827,7 @@ func TestWasDeleted(t *testing.T) {
})
}
}
func TestWasCreated(t *testing.T) {
now := metav1.Now()
zero := metav1.Time{}
@ -894,6 +897,7 @@ func TestSetExternalName(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalName(tc.o, tc.name)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalName(...): -want, +got:\n%s", diff)
}
@ -901,142 +905,321 @@ func TestSetExternalName(t *testing.T) {
}
}
func TestAllowPropagation(t *testing.T) {
fromns := "from-namespace"
from := "from-name"
tons := "to-namespace"
to := "to-name"
func TestGetExternalCreatePending(t *testing.T) {
now := time.Now().Round(time.Second)
tohash := func() string {
h := fnv.New32a()
h.Write([]byte(tons))
h.Write([]byte(to))
return fmt.Sprintf("%x", h.Sum32())
}()
type args struct {
from metav1.Object
to metav1.Object
cases := map[string]struct {
o metav1.Object
want time.Time
}{
"ExternalCreatePendingExists": {
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{AnnotationKeyExternalCreatePending: now.Format(time.RFC3339)}}},
want: now,
},
"NoExternalCreatePending": {
o: &corev1.Pod{},
want: time.Time{},
},
}
type want struct {
from metav1.Object
to metav1.Object
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := GetExternalCreatePending(tc.o)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("GetExternalCreatePending(...): -want, +got:\n%s", diff)
}
})
}
}
func TestSetExternalCreatePending(t *testing.T) {
now := time.Now()
cases := map[string]struct {
o metav1.Object
t time.Time
want metav1.Object
}{
"SetsTheCorrectKey": {
o: &corev1.Pod{},
t: now,
want: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{AnnotationKeyExternalCreatePending: now.Format(time.RFC3339)}}},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalCreatePending(tc.o, tc.t)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalCreatePending(...): -want, +got:\n%s", diff)
}
})
}
}
func TestGetExternalCreateSucceeded(t *testing.T) {
now := time.Now().Round(time.Second)
cases := map[string]struct {
o metav1.Object
want time.Time
}{
"ExternalCreateTimeExists": {
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{AnnotationKeyExternalCreateSucceeded: now.Format(time.RFC3339)}}},
want: now,
},
"NoExternalCreateTime": {
o: &corev1.Pod{},
want: time.Time{},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := GetExternalCreateSucceeded(tc.o)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("GetExternalCreateSucceeded(...): -want, +got:\n%s", diff)
}
})
}
}
func TestSetExternalCreateSucceeded(t *testing.T) {
now := time.Now()
cases := map[string]struct {
o metav1.Object
t time.Time
want metav1.Object
}{
"SetsTheCorrectKey": {
o: &corev1.Pod{},
t: now,
want: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{AnnotationKeyExternalCreateSucceeded: now.Format(time.RFC3339)}}},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalCreateSucceeded(tc.o, tc.t)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalCreateSucceeded(...): -want, +got:\n%s", diff)
}
})
}
}
func TestGetExternalCreateFailed(t *testing.T) {
now := time.Now().Round(time.Second)
cases := map[string]struct {
o metav1.Object
want time.Time
}{
"ExternalCreateFailedExists": {
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{AnnotationKeyExternalCreateFailed: now.Format(time.RFC3339)}}},
want: now,
},
"NoExternalCreateFailed": {
o: &corev1.Pod{},
want: time.Time{},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := GetExternalCreateFailed(tc.o)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("GetExternalCreateFailed(...): -want, +got:\n%s", diff)
}
})
}
}
func TestSetExternalCreateFailed(t *testing.T) {
now := time.Now()
cases := map[string]struct {
o metav1.Object
t time.Time
want metav1.Object
}{
"SetsTheCorrectKey": {
o: &corev1.Pod{},
t: now,
want: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{AnnotationKeyExternalCreateFailed: now.Format(time.RFC3339)}}},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
SetExternalCreateFailed(tc.o, tc.t)
if diff := cmp.Diff(tc.want, tc.o); diff != "" {
t.Errorf("SetExternalCreateFailed(...): -want, +got:\n%s", diff)
}
})
}
}
func TestExternalCreateSucceededDuring(t *testing.T) {
type args struct {
o metav1.Object
d time.Duration
}
cases := map[string]struct {
args args
want want
want bool
}{
"Successful": {
"NotYetSuccessfullyCreated": {
args: args{
from: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{
Namespace: fromns,
Name: from,
Annotations: map[string]string{
"existing": "annotation",
},
}},
to: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{
Namespace: tons,
Name: to,
Annotations: map[string]string{
"existing": "annotation",
},
}},
o: &corev1.Pod{},
d: 1 * time.Minute,
},
want: want{
from: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{
Namespace: fromns,
Name: from,
Annotations: map[string]string{
"existing": "annotation",
AnnotationKeyPropagateToPrefix + tohash: tons + "/" + to,
},
}},
to: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{
Namespace: tons,
Name: to,
Annotations: map[string]string{
"existing": "annotation",
AnnotationKeyPropagateFromNamespace: fromns,
AnnotationKeyPropagateFromName: from,
},
}},
want: false,
},
"SuccessfullyCreatedTooLongAgo": {
args: args{
o: func() metav1.Object {
o := &corev1.Pod{}
t := time.Now().Add(-2 * time.Minute)
SetExternalCreateSucceeded(o, t)
return o
}(),
d: 1 * time.Minute,
},
want: false,
},
"SuccessfullyCreatedWithinDuration": {
args: args{
o: func() metav1.Object {
o := &corev1.Pod{}
t := time.Now().Add(-30 * time.Second)
SetExternalCreateSucceeded(o, t)
return o
}(),
d: 1 * time.Minute,
},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
AllowPropagation(tc.args.from, tc.args.to)
if diff := cmp.Diff(tc.want.from, tc.args.from); diff != "" {
t.Errorf("AllowPropagation(...): -want from, +got from\n%s", diff)
}
if diff := cmp.Diff(tc.want.to, tc.args.to); diff != "" {
t.Errorf("AllowPropagation(...): -want to, +got to\n%s", diff)
got := ExternalCreateSucceededDuring(tc.args.o, tc.args.d)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("ExternalCreateSucceededDuring(...): -want, +got:\n%s", diff)
}
})
}
}
func TestAllowsPropagationFrom(t *testing.T) {
ns := "coolns"
name := "coolname"
func TestExternalCreateIncomplete(t *testing.T) {
now := time.Now().Format(time.RFC3339)
earlier := time.Now().Add(-1 * time.Second).Format(time.RFC3339)
evenEarlier := time.Now().Add(-1 * time.Minute).Format(time.RFC3339)
cases := map[string]struct {
to metav1.Object
want types.NamespacedName
reason string
o metav1.Object
want bool
}{
"Successful": {
to: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyPropagateFromNamespace: ns,
AnnotationKeyPropagateFromName: name,
"CreateNeverPending": {
reason: "If we've never called Create it can't be incomplete.",
o: &corev1.Pod{},
want: false,
},
"CreateSucceeded": {
reason: "If Create succeeded since it was pending, it's complete.",
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyExternalCreateFailed: evenEarlier,
AnnotationKeyExternalCreatePending: earlier,
AnnotationKeyExternalCreateSucceeded: now,
}}},
want: types.NamespacedName{Namespace: ns, Name: name},
want: false,
},
"CreateFailed": {
reason: "If Create failed since it was pending, it's complete.",
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyExternalCreateSucceeded: evenEarlier,
AnnotationKeyExternalCreatePending: earlier,
AnnotationKeyExternalCreateFailed: now,
}}},
want: false,
},
"CreateNeverCompleted": {
reason: "If Create was pending but never succeeded or failed, it's incomplete.",
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyExternalCreatePending: earlier,
}}},
want: true,
},
"RecreateNeverCompleted": {
reason: "If Create is pending and there's an older success we're probably trying to recreate a deleted external resource, and it's incomplete.",
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyExternalCreateSucceeded: earlier,
AnnotationKeyExternalCreatePending: now,
}}},
want: true,
},
"RetryNeverCompleted": {
reason: "If Create is pending and there's an older failure we're probably trying to recreate a deleted external resource, and it's incomplete.",
o: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
AnnotationKeyExternalCreateFailed: earlier,
AnnotationKeyExternalCreatePending: now,
}}},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := AllowsPropagationFrom(tc.to)
got := ExternalCreateIncomplete(tc.o)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("AllowsPropagationFrom(...): -want, +got\n%s", diff)
t.Errorf("ExternalCreateIncomplete(...): -want, +got:\n%s", diff)
}
})
}
}
func TestAllowsPropagationTo(t *testing.T) {
nsA := "coolns"
nameA := "coolname"
nsB := "coolerns"
nameB := "coolername"
func TestIsPaused(t *testing.T) {
cases := map[string]struct {
from metav1.Object
want map[types.NamespacedName]bool
o metav1.Object
want bool
}{
"Successful": {
from: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
"existing": "annotation",
AnnotationKeyPropagateToPrefix + "missingslash": "wat",
AnnotationKeyPropagateToPrefix + "missingname": "wat/",
AnnotationKeyPropagateToPrefix + "missingnamespace": "/wat",
AnnotationKeyPropagateToPrefix + "a": nsA + "/" + nameA,
AnnotationKeyPropagateToPrefix + "b": nsB + "/" + nameB,
}}},
want: map[types.NamespacedName]bool{
{Namespace: nsA, Name: nameA}: true,
{Namespace: nsB, Name: nameB}: true,
},
"HasPauseAnnotationSetTrue": {
o: func() metav1.Object {
p := &corev1.Pod{}
p.SetAnnotations(map[string]string{
AnnotationKeyReconciliationPaused: "true",
})
return p
}(),
want: true,
},
"NoPauseAnnotation": {
o: &corev1.Pod{},
want: false,
},
"HasEmptyPauseAnnotation": {
o: func() metav1.Object {
p := &corev1.Pod{}
p.SetAnnotations(map[string]string{
AnnotationKeyReconciliationPaused: "",
})
return p
}(),
want: false,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := AllowsPropagationTo(tc.from)
got := IsPaused(tc.o)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("AllowsPropagationTo(...): -want, +got\n%s", diff)
t.Errorf("IsPaused(...): -want, +got:\n%s", diff)
}
})
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package parser
import (
"errors"
"io"
"os"
"path/filepath"
@ -50,34 +51,36 @@ type FilterFn func(path string, info os.FileInfo) (bool, error)
// SkipPath skips files at a certain path.
func SkipPath(pattern string) FilterFn {
return func(path string, info os.FileInfo) (bool, error) {
return func(path string, _ os.FileInfo) (bool, error) {
return filepath.Match(pattern, path)
}
}
// SkipDirs skips directories.
func SkipDirs() FilterFn {
return func(path string, info os.FileInfo) (bool, error) {
return func(_ string, info os.FileInfo) (bool, error) {
if info.IsDir() {
return true, nil
}
return false, nil
}
}
// SkipEmpty skips empty files.
func SkipEmpty() FilterFn {
return func(path string, info os.FileInfo) (bool, error) {
return func(_ string, info os.FileInfo) (bool, error) {
return info.Size() == 0, nil
}
}
// SkipNotYAML skips files that do not have YAML extension.
func SkipNotYAML() FilterFn {
return func(path string, info os.FileInfo) (bool, error) {
return func(path string, _ os.FileInfo) (bool, error) {
if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
return true, nil
}
return false, nil
}
}
@ -91,18 +94,23 @@ func NewFsReadCloser(fs afero.Fs, dir string, fns ...FilterFn) (*FsReadCloser, e
if err != nil {
return err
}
for _, fn := range fns {
filter, err := fn(path, info)
if err != nil {
return err
}
if filter {
return nil
}
}
paths = append(paths, path)
return nil
})
return &FsReadCloser{
fs: fs,
dir: dir,
@ -120,24 +128,31 @@ func (r *FsReadCloser) Read(p []byte) (n int, err error) {
r.position = 0
r.wroteBreak = false
n = copy(p, "\n---\n")
return n, nil
}
if r.index == len(r.paths) {
return 0, io.EOF
}
if r.writeBreak {
n = copy(p, "\n...\n")
r.writeBreak = false
r.wroteBreak = true
return n, nil
}
b, err := afero.ReadFile(r.fs, r.paths[r.index])
n = copy(p, b[r.position:])
r.position += n
if err == io.EOF || n == 0 {
if errors.Is(err, io.EOF) || n == 0 {
r.writeBreak = true
err = nil
}
return n, err
}
@ -147,13 +162,14 @@ func (r *FsReadCloser) Close() error {
}
// Annotate returns additional about the data currently being read.
func (r *FsReadCloser) Annotate() interface{} {
func (r *FsReadCloser) Annotate() any {
// Index will be out of bounds if we error after the final file has been
// read.
index := r.index
if index == len(r.paths) {
index--
}
return FsReadCloserAnnotation{
path: r.paths[index],
position: r.position,

20
pkg/parser/fuzz_test.go Normal file
View File

@ -0,0 +1,20 @@
package parser
import (
"bytes"
"context"
"io"
"testing"
"k8s.io/apimachinery/pkg/runtime"
)
func FuzzParse(f *testing.F) {
f.Fuzz(func(_ *testing.T, data []byte) {
objScheme := runtime.NewScheme()
metaScheme := runtime.NewScheme()
p := New(metaScheme, objScheme)
r := io.NopCloser(bytes.NewReader(data))
_, _ = p.Parse(context.Background(), r)
})
}

View File

@ -17,24 +17,27 @@ limitations under the License.
package parser
import (
"github.com/pkg/errors"
"strings"
"k8s.io/apimachinery/pkg/runtime"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
const (
errNilLinterFn = "linter function is nil"
errOrFmt = "object did not pass either check: (%v), (%v)"
errOrFmt = "object did not pass any of the linters with following errors: %s"
)
// A Linter lints packages.
type Linter interface {
Lint(*Package) error
Lint(l Lintable) error
}
// PackageLinterFn lints an entire package. If function applies a check for
// multiple objects, consider using an ObjectLinterFn.
type PackageLinterFn func(*Package) error
type PackageLinterFn func(Lintable) error
// PackageLinterFns is a convenience function to pass multiple PackageLinterFn
// to a function that cannot accept variadic arguments.
@ -69,12 +72,13 @@ func NewPackageLinter(pre []PackageLinterFn, perMeta, perObject []ObjectLinterFn
}
// Lint executes all linter functions against a package.
func (l *PackageLinter) Lint(pkg *Package) error {
func (l *PackageLinter) Lint(pkg Lintable) error {
for _, fn := range l.pre {
if err := fn(pkg); err != nil {
return err
}
}
for _, o := range pkg.GetMeta() {
for _, fn := range l.perMeta {
if err := fn(o); err != nil {
@ -82,6 +86,7 @@ func (l *PackageLinter) Lint(pkg *Package) error {
}
}
}
for _, o := range pkg.GetObjects() {
for _, fn := range l.perObject {
if err := fn(o); err != nil {
@ -89,21 +94,29 @@ func (l *PackageLinter) Lint(pkg *Package) error {
}
}
}
return nil
}
// Or checks that at least one of the passed linter functions does not return an
// error.
func Or(a, b ObjectLinterFn) ObjectLinterFn {
func Or(linters ...ObjectLinterFn) ObjectLinterFn {
return func(o runtime.Object) error {
if a == nil || b == nil {
return errors.New(errNilLinterFn)
var errs []string
for _, l := range linters {
if l == nil {
return errors.New(errNilLinterFn)
}
err := l(o)
if err == nil {
return nil
}
errs = append(errs, err.Error())
}
aErr := a(o)
bErr := b(o)
if aErr == nil || bErr == nil {
return nil
}
return errors.Errorf(errOrFmt, aErr, bErr)
return errors.Errorf(errOrFmt, strings.Join(errs, ", "))
}
}

View File

@ -20,9 +20,9 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"github.com/crossplane/crossplane-runtime/pkg/errors"
"github.com/crossplane/crossplane-runtime/pkg/test"
)
@ -31,16 +31,16 @@ var _ Linter = &PackageLinter{}
var (
errBoom = errors.New("boom")
pkgPass = func(pkg *Package) error {
pkgPass = func(_ Lintable) error {
return nil
}
pkgFail = func(pkg *Package) error {
pkgFail = func(_ Lintable) error {
return errBoom
}
objPass = func(o runtime.Object) error {
objPass = func(_ runtime.Object) error {
return nil
}
objFail = func(o runtime.Object) error {
objFail = func(_ runtime.Object) error {
return errBoom
}
)
@ -112,14 +112,13 @@ func TestLinter(t *testing.T) {
objects: []runtime.Object{crd},
},
},
err: errors.Errorf(errOrFmt, errBoom, errBoom),
err: errors.Errorf(errOrFmt, errBoom.Error()+", "+errBoom.Error()),
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
err := tc.args.linter.Lint(tc.args.pkg)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nl.Lint(...): -want error, +got error:\n%s", tc.reason, diff)
}
@ -160,7 +159,7 @@ func TestOr(t *testing.T) {
one: objFail,
two: objFail,
},
err: errors.Errorf(errOrFmt, errBoom, errBoom),
err: errors.Errorf(errOrFmt, errBoom.Error()+", "+errBoom.Error()),
},
"ErrNilLinter": {
reason: "Passing a nil linter will should always return error.",
@ -175,7 +174,6 @@ func TestOr(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
err := Or(tc.args.one, tc.args.two)(crd)
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nOr(...): -want error, +got error:\n%s", tc.reason, diff)
}

View File

@ -14,31 +14,40 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package parser implements a parser for Crossplane packages.
package parser
import (
"bufio"
"context"
"fmt"
"io"
"io/ioutil"
"strings"
"unicode"
"github.com/pkg/errors"
"github.com/spf13/afero"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/kubernetes"
"github.com/crossplane/crossplane-runtime/pkg/errors"
)
// Lintable defines the common API for lintable packages.
type Lintable interface {
// GetMeta returns metadata objects of the lintable package, such as
// Provider, Configuration or Function.
GetMeta() []runtime.Object
// GetObjects returns objects of the lintable package.
GetObjects() []runtime.Object
}
// AnnotatedReadCloser is a wrapper around io.ReadCloser that allows
// implementations to supply additional information about data that is read.
type AnnotatedReadCloser interface {
io.ReadCloser
Annotate() interface{}
Annotate() any
}
// ObjectCreaterTyper know how to create and determine the type of objects.
@ -70,7 +79,7 @@ func (p *Package) GetObjects() []runtime.Object {
// Parser is a package parser.
type Parser interface {
Parse(context.Context, io.ReadCloser) (*Package, error)
Parse(ctx context.Context, rc io.ReadCloser) (*Package, error)
}
// PackageParser is a Parser implementation for parsing packages.
@ -91,62 +100,88 @@ func New(meta, obj ObjectCreaterTyper) *PackageParser {
// decode objects recognized by the meta scheme, then attempts to decode objects
// recognized by the object scheme. Objects not recognized by either scheme
// return an error rather than being skipped.
func (p *PackageParser) Parse(ctx context.Context, reader io.ReadCloser) (*Package, error) { //nolint:gocyclo
func (p *PackageParser) Parse(_ context.Context, reader io.ReadCloser) (*Package, error) {
pkg := NewPackage()
if reader == nil {
return pkg, nil
}
defer func() { _ = reader.Close() }()
yr := yaml.NewYAMLReader(bufio.NewReader(reader))
dm := json.NewSerializerWithOptions(json.DefaultMetaFactory, p.metaScheme, p.metaScheme, json.SerializerOptions{Yaml: true})
do := json.NewSerializerWithOptions(json.DefaultMetaFactory, p.objScheme, p.objScheme, json.SerializerOptions{Yaml: true})
for {
bytes, err := yr.Read()
if err != nil && err != io.EOF {
content, err := yr.Read()
if err != nil && !errors.Is(err, io.EOF) {
return pkg, err
}
if err == io.EOF {
if errors.Is(err, io.EOF) {
break
}
if len(bytes) == 0 {
if isEmptyYAML(content) {
continue
}
m, _, err := dm.Decode(bytes, nil, nil)
m, _, err := dm.Decode(content, nil, nil)
if err != nil {
o, _, err := do.Decode(bytes, nil, nil)
if err != nil {
empty := true
for _, b := range bytes {
if !unicode.IsSpace(rune(b)) {
empty = false
break
}
}
// If the YAML document only contains Unicode White Space we
// ignore and do not return an error.
if empty {
continue
}
if anno, ok := reader.(AnnotatedReadCloser); ok {
return pkg, errors.Wrap(err, fmt.Sprintf("%+v", anno.Annotate()))
}
return pkg, err
// NOTE(hasheddan): we only try to decode with object scheme if the
// error is due the object not being registered in the meta scheme.
if !runtime.IsNotRegisteredError(err) {
return pkg, annotateErr(err, reader)
}
o, _, err := do.Decode(content, nil, nil)
if err != nil {
return pkg, annotateErr(err, reader)
}
pkg.objects = append(pkg.objects, o)
continue
}
pkg.meta = append(pkg.meta, m)
}
return pkg, nil
}
// isEmptyYAML checks whether the provided YAML can be considered empty. This
// is useful for filtering out empty YAML documents that would otherwise
// cause issues when decoded.
func isEmptyYAML(y []byte) bool {
for _, line := range strings.Split(string(y), "\n") {
trimmed := strings.TrimLeftFunc(line, unicode.IsSpace)
// We don't want to return an empty document with only separators that
// have nothing in-between.
if trimmed != "" && trimmed != "---" && trimmed != "..." && !strings.HasPrefix(trimmed, "#") {
return false
}
}
return true
}
// annotateErr annotates an error if the reader is an AnnotatedReadCloser.
func annotateErr(err error, reader io.ReadCloser) error {
if anno, ok := reader.(AnnotatedReadCloser); ok {
return errors.Wrapf(err, "%+v", anno.Annotate())
}
return err
}
// BackendOption modifies the parser backend. Backends may accept options at
// creation time, but must accept them at initialization.
type BackendOption func(Backend)
// Backend provides a source for a parser.
type Backend interface {
Init(context.Context, ...BackendOption) (io.ReadCloser, error)
Init(ctx context.Context, o ...BackendOption) (io.ReadCloser, error)
}
// PodLogBackend is a parser backend that uses Kubernetes pod logs as source.
@ -162,6 +197,7 @@ func NewPodLogBackend(bo ...BackendOption) *PodLogBackend {
for _, o := range bo {
o(p)
}
return p
}
@ -170,11 +206,14 @@ func (p *PodLogBackend) Init(ctx context.Context, bo ...BackendOption) (io.ReadC
for _, o := range bo {
o(p)
}
logs := p.client.CoreV1().Pods(p.namespace).GetLogs(p.name, &corev1.PodLogOptions{})
reader, err := logs.Stream(ctx)
if err != nil {
return nil, err
}
return reader, nil
}
@ -185,6 +224,7 @@ func PodName(name string) BackendOption {
if !ok {
return
}
pl.name = name
}
}
@ -196,6 +236,7 @@ func PodNamespace(namespace string) BackendOption {
if !ok {
return
}
pl.namespace = namespace
}
}
@ -207,6 +248,7 @@ func PodClient(client kubernetes.Interface) BackendOption {
if !ok {
return
}
pl.client = client
}
}
@ -220,7 +262,7 @@ func NewNopBackend(...BackendOption) *NopBackend {
}
// Init initializes a NopBackend.
func (p *NopBackend) Init(ctx context.Context, bo ...BackendOption) (io.ReadCloser, error) {
func (p *NopBackend) Init(_ context.Context, _ ...BackendOption) (io.ReadCloser, error) {
return nil, nil
}
@ -239,14 +281,16 @@ func NewFsBackend(fs afero.Fs, bo ...BackendOption) *FsBackend {
for _, o := range bo {
o(f)
}
return f
}
// Init initializes an FsBackend.
func (p *FsBackend) Init(ctx context.Context, bo ...BackendOption) (io.ReadCloser, error) {
func (p *FsBackend) Init(_ context.Context, bo ...BackendOption) (io.ReadCloser, error) {
for _, o := range bo {
o(p)
}
return NewFsReadCloser(p.fs, p.dir, p.skips...)
}
@ -257,6 +301,7 @@ func FsDir(dir string) BackendOption {
if !ok {
return
}
f.dir = dir
}
}
@ -268,6 +313,7 @@ func FsFilters(skips ...FilterFn) BackendOption {
if !ok {
return
}
f.skips = skips
}
}
@ -285,9 +331,10 @@ func NewEchoBackend(echo string) Backend {
}
// Init initializes an EchoBackend.
func (p *EchoBackend) Init(ctx context.Context, bo ...BackendOption) (io.ReadCloser, error) {
func (p *EchoBackend) Init(_ context.Context, bo ...BackendOption) (io.ReadCloser, error) {
for _, o := range bo {
o(p)
}
return ioutil.NopCloser(strings.NewReader(p.echo)), nil
return io.NopCloser(strings.NewReader(p.echo)), nil
}

View File

@ -55,6 +55,22 @@ metadata:
deployBytes = []byte(`apiVersion: apps/v1
kind: Deployment
metadata:
name: test
annotations:
crossplane.io/managed: |
#!/bin/bash some script
some script
`)
commentedOutBytes = []byte(`# apiVersion: apps/v1
# kind: Deployment
# metadata:
# name: test`)
manifestWithComments = []byte(`
apiVersion: apiextensions.k8s.io/v1beta1
# Some Comment
kind: CustomResourceDefinition
metadata:
name: test`)
@ -79,6 +95,9 @@ func TestParser(t *testing.T) {
emptyFs := afero.NewMemMapFs()
_ = afero.WriteFile(emptyFs, "empty.yaml", []byte(""), 0o644)
_ = afero.WriteFile(emptyFs, "bad.yam", []byte("definitely not yaml"), 0o644)
commentedFs := afero.NewMemMapFs()
_ = afero.WriteFile(commentedFs, "commented.yaml", commentedOutBytes, 0o644)
_ = afero.WriteFile(commentedFs, ".crossplane/realmanifest.yaml", manifestWithComments, 0o644)
objScheme := runtime.NewScheme()
_ = apiextensions.AddToScheme(objScheme)
metaScheme := runtime.NewScheme()
@ -128,6 +147,24 @@ func TestParser(t *testing.T) {
objects: []runtime.Object{crd, crd, crd, crd},
},
},
"FsBackendCommentedOut": {
reason: "should parse filesystem successfully even if all the files are commented out",
parser: New(metaScheme, objScheme),
backend: NewFsBackend(commentedFs, FsDir("."), FsFilters(SkipDirs(), SkipNotYAML(), SkipPath(".crossplane/*"))),
pkg: &Package{
meta: nil,
objects: nil,
},
},
"FsBackendWithComments": {
reason: "should parse filesystem successfully when some of the manifests contain comments",
parser: New(metaScheme, objScheme),
backend: NewFsBackend(commentedFs, FsDir("."), FsFilters(SkipDirs(), SkipNotYAML())),
pkg: &Package{
meta: nil,
objects: []runtime.Object{crd},
},
},
"FsBackendAll": {
reason: "should parse filesystem successfully with multiple objects in single file",
parser: New(metaScheme, objScheme),
@ -158,18 +195,22 @@ func TestParser(t *testing.T) {
if err != nil {
t.Errorf("backend.Init(...): unexpected error: %s", err)
}
pkg, err := tc.parser.Parse(context.TODO(), r)
if err != nil && !tc.wantErr {
t.Errorf("parser.Parse(...): unexpected error: %s", err)
}
if tc.wantErr {
return
}
if diff := cmp.Diff(tc.pkg.GetObjects(), pkg.GetObjects(), cmpopts.SortSlices(func(i, j runtime.Object) bool {
return i.GetObjectKind().GroupVersionKind().String() > j.GetObjectKind().GroupVersionKind().String()
})); diff != "" {
t.Errorf("Objects: -want, +got:\n%s", diff)
}
if diff := cmp.Diff(tc.pkg.GetMeta(), pkg.GetMeta(), cmpopts.SortSlices(func(i, j runtime.Object) bool {
return i.GetObjectKind().GroupVersionKind().String() > j.GetObjectKind().GroupVersionKind().String()
})); diff != "" {
@ -178,3 +219,93 @@ func TestParser(t *testing.T) {
})
}
}
func TestCleanYAML(t *testing.T) {
type args struct {
in []byte
}
type want struct {
out bool
}
cases := map[string]struct {
reason string
args args
want want
}{
"Empty": {
reason: "Should return true on empty input",
args: args{in: []byte("")},
want: want{out: true},
},
"EmptyLine": {
reason: "Should return true on an input with an empty line",
args: args{in: []byte("\n")},
want: want{out: true},
},
"WhitespaceOnly": {
reason: "Should return true on an input with only whitespaces",
args: args{in: []byte(" \n\t ")},
want: want{out: true},
},
"OnlyYAMLSeparators": {
reason: "Should return true on an input with only YAML separators",
args: args{in: []byte("---\n...")},
want: want{out: true},
},
"YAMLWithWhitespaceLineAndNonEmptyLine": {
reason: "Should return false on having whitespace and non empty line in the input",
args: args{in: []byte(" \nkey: value")},
want: want{out: false},
},
"CommentedOut": {
reason: "Should return true on a fully commented out input",
args: args{in: []byte(`# apiVersion: apps/v1
# kind: Deployment
# metadata:
# name: test`)},
want: want{out: true},
},
"CommentedOutExceptSeparator": {
reason: "Should return true on a fully commented out input with a separator not commented",
args: args{in: []byte(`---
# apiVersion: apps/v1
# kind: Deployment
# metadata:
# name: test`)},
want: want{out: true},
},
"NotFullyCommentedOut": {
reason: "Should return false on a partially commented out input",
args: args{in: []byte(`---
# some comment
apiVersion: apps/v1
kind: Deployment
metadata:
name: test`)},
want: want{out: false},
},
"ShebangAnnotation": {
reason: "Should return false with just a shebang annotation",
args: args{in: []byte(`---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
annotations:
someScriptWithAShebang: |
#!/bin/bash
some script`)},
want: want{out: false},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := isEmptyYAML(tc.args.in)
if diff := cmp.Diff(tc.want.out, got); diff != "" {
t.Errorf("isEmptyYAML: -want, +got:\n%s", diff)
}
})
}
}

View File

@ -32,6 +32,8 @@ type Settings struct {
}
// Default password generation settings.
//
//nolint:gochecknoglobals // We treat this as a constant.
var Default = Settings{
CharacterSet: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
Length: 27,
@ -46,12 +48,14 @@ func Generate() (string, error) {
// Generate a password.
func (s Settings) Generate() (string, error) {
pw := make([]byte, s.Length)
for i := 0; i < s.Length; i++ {
for i := range s.Length {
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(s.CharacterSet))))
if err != nil {
return "", err
}
pw[i] = s.CharacterSet[n.Int64()]
}
return string(pw), nil
}

View File

@ -8,12 +8,13 @@ import (
func TestGenerate(t *testing.T) {
// ¯\_(ツ)_/¯
want := "aaa"
got, err := Settings{CharacterSet: "a", Length: 3}.Generate()
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("Generate(): -want, +got:\n%s", diff)
}
if err != nil {
t.Errorf("Generate: %s\n", err)
}

View File

@ -14,34 +14,44 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package ratelimiter contains suggested default ratelimiters for Crossplane.
package ratelimiter
import (
"time"
"golang.org/x/time/rate"
"k8s.io/client-go/rest"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// DefaultProviderRPS is the recommended default average requeues per second
// tolerated by a provider's controller manager.
const DefaultProviderRPS = 1
// NewDefaultProviderRateLimiter returns a token bucket rate limiter meant for
// limiting the number of average total requeues per second for all controllers
// registered with a controller manager. The bucket size is a linear function of
// the requeues per second.
func NewDefaultProviderRateLimiter(rps int) *workqueue.BucketRateLimiter {
return &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(rps), rps*10)}
// NewGlobal returns a token bucket rate limiter meant for limiting the number
// of average total requeues per second for all controllers registered with a
// controller manager. The bucket size (i.e. allowed burst) is rps * 10.
func NewGlobal(rps int) *BucketRateLimiter {
return &workqueue.TypedBucketRateLimiter[string]{Limiter: rate.NewLimiter(rate.Limit(rps), rps*10)}
}
// NewDefaultManagedRateLimiter returns a rate limiter that takes the maximum
// delay between the passed provider and a per-item exponential backoff limiter.
// The exponential backoff limiter has a base delay of 1s and a maximum of 60s.
func NewDefaultManagedRateLimiter(provider ratelimiter.RateLimiter) ratelimiter.RateLimiter {
return workqueue.NewMaxOfRateLimiter(
workqueue.NewItemExponentialFailureRateLimiter(1*time.Second, 60*time.Second),
provider,
)
// ControllerRateLimiter to work with [sigs.k8s.io/controller-runtime/pkg/controller.Options].
type ControllerRateLimiter = workqueue.TypedRateLimiter[reconcile.Request]
// NewController returns a rate limiter that takes the maximum delay between the
// passed rate limiter and a per-item exponential backoff limiter. The
// exponential backoff limiter has a base delay of 1s and a maximum of 60s.
func NewController() ControllerRateLimiter {
return workqueue.NewTypedItemExponentialFailureRateLimiter[reconcile.Request](1*time.Second, 60*time.Second)
}
// LimitRESTConfig returns a copy of the supplied REST config with rate limits
// derived from the supplied rate of reconciles per second.
func LimitRESTConfig(cfg *rest.Config, rps int) *rest.Config {
// The Kubernetes controller manager and controller-runtime controller
// managers use 20qps with 30 burst. We default to 10 reconciles per
// second so our defaults are designed to accommodate that.
out := rest.CopyConfig(cfg)
out.QPS = float32(rps * 5)
out.Burst = rps * 10
return out
}

View File

@ -0,0 +1,98 @@
/*
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.
*/
package ratelimiter
import (
"context"
"sync"
"time"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// BucketRateLimiter for a standard crossplane reconciler.
type BucketRateLimiter = workqueue.TypedBucketRateLimiter[string]
// RateLimiter for a standard crossplane reconciler.
type RateLimiter = workqueue.TypedRateLimiter[string]
// A Reconciler rate limits an inner, wrapped Reconciler. Requests that are rate
// limited immediately return RequeueAfter: d without calling the wrapped
// Reconciler, where d is imposed by the rate limiter.
type Reconciler struct {
name string
inner reconcile.Reconciler
limit RateLimiter
limited map[string]struct{}
limitedL sync.RWMutex
}
// NewReconciler wraps the supplied Reconciler, ensuring requests are passed to
// it no more frequently than the supplied RateLimiter allows. Multiple uniquely
// named Reconcilers can share the same RateLimiter.
func NewReconciler(name string, r reconcile.Reconciler, l RateLimiter) *Reconciler {
return &Reconciler{name: name, inner: r, limit: l, limited: make(map[string]struct{})}
}
// Reconcile the supplied request subject to rate limiting.
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
item := r.name + req.String()
if d := r.when(req); d > 0 {
return reconcile.Result{RequeueAfter: d}, nil
}
r.limit.Forget(item)
return r.inner.Reconcile(ctx, req)
}
// when adapts the upstream rate limiter's 'When' method such that rate limited
// requests can call it again when they return and will be allowed to proceed
// immediately without being subject to further rate limiting. It is optimised
// for handling requests that have not been and will not be rate limited without
// blocking.
func (r *Reconciler) when(req reconcile.Request) time.Duration {
item := r.name + req.String()
r.limitedL.RLock()
_, limited := r.limited[item]
r.limitedL.RUnlock()
// If we already rate limited this request we trust that it complied and
// let it pass immediately.
if limited {
r.limitedL.Lock()
delete(r.limited, item)
r.limitedL.Unlock()
return 0
}
d := r.limit.When(item)
// Record that this request was rate limited so that we can let it
// through immediately when it requeues after the supplied duration.
if d != 0 {
r.limitedL.Lock()
r.limited[item] = struct{}{}
r.limitedL.Unlock()
}
return d
}

Some files were not shown because too many files have changed in this diff Show More