Compare commits
No commits in common. "main" and "v1.14.0-rc.1" have entirely different histories.
main
...
v1.14.0-rc
|
@ -1,32 +1,35 @@
|
|||
<!--
|
||||
Thank you for helping to improve Crossplane! Please read the contribution docs
|
||||
(linked below) if this is your first Crossplane pull request.
|
||||
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.
|
||||
-->
|
||||
|
||||
### Description of your changes
|
||||
|
||||
<!--
|
||||
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.
|
||||
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":
|
||||
|
||||
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 #
|
||||
|
||||
Fixes #
|
||||
|
||||
I have: <!--You MUST either [x] check or [ ] ~strike through~ every item.-->
|
||||
I have:
|
||||
|
||||
- [ ] Read and followed Crossplane's [contribution process].
|
||||
- [ ] 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.
|
||||
- [ ] Run `make reviewable test` to ensure this PR is ready for review.
|
||||
|
||||
Need help with this checklist? See the [cheat sheet].
|
||||
### How has this code been tested
|
||||
|
||||
[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
|
||||
<!--
|
||||
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
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#!/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
|
|
@ -1,211 +1,63 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended",
|
||||
"helpers:pinGitHubActionDigests",
|
||||
":semanticCommits"
|
||||
"config:base",
|
||||
"helpers:pinGitHubActionDigests"
|
||||
],
|
||||
// We only want renovate to rebase PRs when they have conflicts, default
|
||||
// "auto" mode is not required.
|
||||
// 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
|
||||
// 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": [
|
||||
"postUpdateOptions": ["gomodTidy"],
|
||||
// By default renovate will auto detect whether semantic commits have been used
|
||||
// in the recent history and comply with that, we explicitly disable it
|
||||
"semanticCommits": "disabled",
|
||||
// All PRs should have a label
|
||||
"labels": ["automated"],
|
||||
"regexManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
"description": "Bump Earthly version in GitHub workflows",
|
||||
"fileMatch": [
|
||||
"^\\.github\\/workflows\\/[^/]+\\.ya?ml$"
|
||||
],
|
||||
"description": "Bump Go version ued in 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"
|
||||
"GO_VERSION: '(?<currentValue>.*?)'\\n"
|
||||
],
|
||||
"datasourceTemplate": "golang-version",
|
||||
"depNameTemplate": "golang"
|
||||
},
|
||||
{
|
||||
"customType": "regex",
|
||||
"description": "Bump golangci-lint version in the Earthfile",
|
||||
"fileMatch": [
|
||||
"^Earthfile$"
|
||||
],
|
||||
}, {
|
||||
"description": "Bump golangci-lint version in workflows and the Makefile",
|
||||
"fileMatch": ["^\\.github\\/workflows\\/[^/]+\\.ya?ml$","^Makefile$"],
|
||||
"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$"
|
||||
"GOLANGCI_VERSION: 'v(?<currentValue>.*?)'\\n",
|
||||
"GOLANGCILINT_VERSION = (?<currentValue>.*?)\\n"
|
||||
],
|
||||
"datasourceTemplate": "github-tags",
|
||||
"depNameTemplate": "golangci/golangci-lint",
|
||||
"extractVersionTemplate": "^v(?<version>.*)$"
|
||||
}, {
|
||||
"description": "Bump Go required version in workflows and the Makefile",
|
||||
"fileMatch": ["^\\.github\\/workflows\\/[^/]+\\.ya?ml$", "^Makefile$"],
|
||||
"matchStrings": [
|
||||
"ARG CODEQL_VERSION=(?<currentValue>.*?)\\n"
|
||||
"GO_REQUIRED_VERSION = (?<currentValue>.*?)\\n",
|
||||
],
|
||||
"datasourceTemplate": "github-releases",
|
||||
"depNameTemplate": "github/codeql-action",
|
||||
"extractVersionTemplate": "^codeql-bundle-(?<version>.*)$"
|
||||
},
|
||||
"datasourceTemplate": "golang-version",
|
||||
"depNameTemplate": "golang",
|
||||
"versioningTemplate": "loose",
|
||||
"extractVersionTemplate": "^(?<version>\\d+\\.\\d+)"
|
||||
}
|
||||
],
|
||||
// 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
|
||||
// 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": "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"
|
||||
|
@ -213,35 +65,32 @@
|
|||
"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"
|
||||
],
|
||||
"allowedVersions": "<1.0"
|
||||
}, {
|
||||
"description": "Only get dependency digest updates every month to reduce noise",
|
||||
"matchDatasources": [
|
||||
"go"
|
||||
],
|
||||
"matchUpdateTypes": [
|
||||
"digest",
|
||||
],
|
||||
"extends": [
|
||||
"schedule:monthly"
|
||||
"extends": ["schedule:monthly"],
|
||||
}, {
|
||||
"description": "Single PR for all kubernetes dependency updates, as they usually are all linked",
|
||||
"matchDatasources": [
|
||||
"go"
|
||||
],
|
||||
},
|
||||
{
|
||||
"groupName": "kubernetes deps",
|
||||
"matchUpdateTypes": [
|
||||
"major",
|
||||
"minor",
|
||||
"patch"
|
||||
],
|
||||
"matchPackagePrefixes": [
|
||||
"k8s.io",
|
||||
"sigs.k8s.io"
|
||||
]
|
||||
}, {
|
||||
"description": "Ignore oss-fuzz, it's not using tags, we'll stick to master",
|
||||
"matchDepTypes": [
|
||||
"action"
|
||||
|
@ -250,13 +99,6 @@
|
|||
"google/oss-fuzz"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"description": "Group all go version updates",
|
||||
"matchDatasources": [
|
||||
"golang-version"
|
||||
],
|
||||
"groupName": "golang version",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# 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
|
|
@ -22,12 +22,12 @@ jobs:
|
|||
if: github.event.pull_request.merged
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Open Backport PR
|
||||
uses: zeebe-io/backport-action@ef20d86abccbac3ee3a73cb2efbdc06344c390e5 # v2.5.0
|
||||
uses: zeebe-io/backport-action@bd68141f079bd036e45ea8149bc9d174d5a04703 # v1.4.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github_workspace: ${{ github.workspace }}
|
||||
|
|
|
@ -3,22 +3,15 @@ name: CI
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- release-*
|
||||
pull_request: {}
|
||||
workflow_dispatch: {}
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
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 }}
|
||||
GO_VERSION: '1.21.3'
|
||||
GOLANGCI_VERSION: 'v1.54.2'
|
||||
|
||||
jobs:
|
||||
check-diff:
|
||||
|
@ -26,220 +19,209 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
|
||||
- name: Setup Earthly
|
||||
uses: earthly/actions-setup@v1
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: ${{ env.EARTHLY_VERSION }}
|
||||
submodules: true
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
if: env.DOCKER_USR != ''
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USR }}
|
||||
password: ${{ secrets.DOCKER_PSW }}
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
- name: Find the Go Build Cache
|
||||
id: go
|
||||
run: echo "::set-output name=cache::$(make go.cachedir)"
|
||||
|
||||
- name: Cache the Go Build Cache
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: ${{ steps.go.outputs.cache }}
|
||||
key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-build-check-diff-
|
||||
|
||||
- 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
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
script: core.setFailed('Found changed files after running earthly +generate.')
|
||||
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
|
||||
|
||||
detect-noop:
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
noop: ${{ steps.noop.outputs.should_skip }}
|
||||
steps:
|
||||
- name: Detect No-op Changes
|
||||
id: noop
|
||||
uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
paths_ignore: '["**.md", "**.png", "**.jpg"]'
|
||||
do_not_skip: '["workflow_dispatch", "schedule", "push"]'
|
||||
concurrent_skipping: false
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: detect-noop
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
|
||||
- name: Setup Earthly
|
||||
uses: earthly/actions-setup@v1
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: ${{ env.EARTHLY_VERSION }}
|
||||
submodules: true
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
if: env.DOCKER_USR != ''
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USR }}
|
||||
password: ${{ secrets.DOCKER_PSW }}
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
- name: Find the Go Build Cache
|
||||
id: go
|
||||
run: echo "::set-output name=cache::$(make go.cachedir)"
|
||||
|
||||
- name: Cache the Go Build Cache
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: ${{ steps.go.outputs.cache }}
|
||||
key: ${{ runner.os }}-build-lint-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-build-lint-
|
||||
|
||||
- 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: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-pkg-
|
||||
|
||||
- name: Vendor Dependencies
|
||||
run: make vendor vendor.check
|
||||
|
||||
# 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
|
||||
run: earthly --strict --remote-cache ghcr.io/crossplane/crossplane-runtime-earthly-cache:${{ github.job }} +lint
|
||||
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3
|
||||
with:
|
||||
version: ${{ env.GOLANGCI_VERSION }}
|
||||
skip-cache: true # We do our own caching.
|
||||
|
||||
codeql:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: detect-noop
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
|
||||
- name: Setup Earthly
|
||||
uses: earthly/actions-setup@v1
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: ${{ env.EARTHLY_VERSION }}
|
||||
submodules: true
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
if: env.DOCKER_USR != ''
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USR }}
|
||||
password: ${{ secrets.DOCKER_PSW }}
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
- name: Find the Go Build Cache
|
||||
id: go
|
||||
run: echo "::set-output name=cache::$(make go.cachedir)"
|
||||
|
||||
- name: Cache the Go Build Cache
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: ${{ steps.go.outputs.cache }}
|
||||
key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-build-check-diff-
|
||||
|
||||
- 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
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
sarif_file: '_output/codeql/go.sarif'
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-pkg-
|
||||
|
||||
- name: Vendor Dependencies
|
||||
run: make vendor vendor.check
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2
|
||||
with:
|
||||
languages: go
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2
|
||||
|
||||
trivy-scan-fs:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: detect-noop
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Run Trivy vulnerability scanner in fs mode
|
||||
uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0
|
||||
uses: aquasecurity/trivy-action@fbd16365eb88e12433951383f5e99bd901fc618f # 0.12.0
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
ignore-unfixed: true
|
||||
skip-dirs: design
|
||||
scan-ref: '.'
|
||||
exit-code: '1'
|
||||
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
|
||||
needs: detect-noop
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
|
||||
- name: Setup Earthly
|
||||
uses: earthly/actions-setup@v1
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: ${{ env.EARTHLY_VERSION }}
|
||||
submodules: true
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
if: env.DOCKER_USR != ''
|
||||
- name: Fetch History
|
||||
run: git fetch --prune --unshallow
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USR }}
|
||||
password: ${{ secrets.DOCKER_PSW }}
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
||||
- name: Find the Go Build Cache
|
||||
id: go
|
||||
run: echo "::set-output name=cache::$(make go.cachedir)"
|
||||
|
||||
- name: Cache the Go Build Cache
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: ${{ steps.go.outputs.cache }}
|
||||
key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-build-unit-tests-
|
||||
|
||||
- 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: Cache Go Dependencies
|
||||
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
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: earthly --strict --remote-cache ghcr.io/crossplane/crossplane-runtime-earthly-cache:${{ github.job }} +test
|
||||
run: make -j2 test
|
||||
|
||||
- name: Publish Unit Test Coverage
|
||||
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
|
||||
uses: codecov/codecov-action@c4cf8a4f03f0ac8585acb7c1b7ce3460ec15782f # 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 }}
|
||||
file: _output/tests/linux_amd64/coverage.txt
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
allow-edits: "false"
|
||||
permission-level: write
|
||||
- name: Handle Command
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
|
||||
env:
|
||||
POINTS: ${{ steps.command.outputs.command-arguments }}
|
||||
with:
|
||||
|
@ -80,32 +80,12 @@ jobs:
|
|||
permission-level: write
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Open Backport PR
|
||||
uses: zeebe-io/backport-action@ef20d86abccbac3ee3a73cb2efbdc06344c390e5 # v2.5.0
|
||||
uses: zeebe-io/backport-action@bd68141f079bd036e45ea8149bc9d174d5a04703 # v1.4.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
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
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-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Fetch History
|
||||
run: git fetch --prune --unshallow
|
||||
|
||||
- name: Login to Docker
|
||||
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3
|
||||
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 }}
|
|
@ -1,54 +0,0 @@
|
|||
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
|
|
@ -1,47 +0,0 @@
|
|||
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.
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
|
||||
- name: Create Tag
|
||||
uses: negz/create-tag@39bae1e0932567a58c20dea5a1a0d18358503320 # v1
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "build"]
|
||||
path = build
|
||||
url = https://github.com/upbound/build
|
204
.golangci.yml
204
.golangci.yml
|
@ -1,101 +1,12 @@
|
|||
run:
|
||||
timeout: 10m
|
||||
|
||||
skip-files:
|
||||
- "zz_generated\\..+\\.go$"
|
||||
|
||||
output:
|
||||
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
|
||||
formats:
|
||||
- format: colored-line-number
|
||||
path: stderr
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
fast: false
|
||||
|
||||
disable:
|
||||
# These linters are all deprecated. We disable them explicitly to avoid the
|
||||
# linter logging deprecation warnings.
|
||||
- tenv
|
||||
|
||||
# These are linters we'd like to enable, but that will be labor intensive to
|
||||
# make existing code compliant.
|
||||
- wrapcheck
|
||||
- varnamelen
|
||||
- testpackage
|
||||
- paralleltest
|
||||
- nilnil
|
||||
|
||||
# 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
|
||||
- cyclop
|
||||
- nestif
|
||||
- funlen
|
||||
- maintidx
|
||||
|
||||
# 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
|
||||
format: colored-line-number
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
|
@ -107,10 +18,14 @@ linters-settings:
|
|||
# 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
|
||||
disable:
|
||||
- shadow
|
||||
check-shadowing: false
|
||||
|
||||
gofmt:
|
||||
# simplify code: gofmt with `-s` option, true by default
|
||||
|
@ -122,10 +37,17 @@ linters-settings:
|
|||
- standard
|
||||
- default
|
||||
- prefix(github.com/crossplane/crossplane-runtime)
|
||||
- prefix(github.com/crossplane/crossplane)
|
||||
- blank
|
||||
- dot
|
||||
|
||||
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
|
||||
|
@ -145,8 +67,7 @@ linters-settings:
|
|||
# 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.
|
||||
exported-is-used: true
|
||||
exported-fields-are-used: true
|
||||
check-exported: false
|
||||
|
||||
unparam:
|
||||
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
|
||||
|
@ -185,52 +106,52 @@ linters-settings:
|
|||
require-explanation: true
|
||||
require-specific: true
|
||||
|
||||
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"
|
||||
|
||||
interfacebloat:
|
||||
max: 5
|
||||
linters:
|
||||
enable:
|
||||
- megacheck
|
||||
- govet
|
||||
- gocyclo
|
||||
- gocritic
|
||||
- goconst
|
||||
- gci
|
||||
- gofmt # We enable this as well as goimports for its simplify mode.
|
||||
- prealloc
|
||||
- revive
|
||||
- unconvert
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
|
||||
disable:
|
||||
# These linters are all deprecated as of golangci-lint v1.49.0. We disable
|
||||
# them explicitly to avoid the linter logging deprecation warnings.
|
||||
- deadcode
|
||||
- varcheck
|
||||
- scopelint
|
||||
- structcheck
|
||||
- interfacer
|
||||
|
||||
tagliatelle:
|
||||
case:
|
||||
rules:
|
||||
json: goCamel
|
||||
presets:
|
||||
- bugs
|
||||
- unused
|
||||
fast: false
|
||||
|
||||
recvcheck:
|
||||
exclusions:
|
||||
- "*.DeepCopy" # DeepCopy* methods are generated and always use a pointer receiver, which may conflict with other methods for a given type.
|
||||
- "*.DeepCopyInto"
|
||||
|
||||
issues:
|
||||
# Excluding generated files.
|
||||
exclude-files:
|
||||
- "zz_generated\\..+\\.go$"
|
||||
- ".+\\.pb.go$"
|
||||
# Excluding configuration per-path and per-linter.
|
||||
# Excluding configuration per-path and per-linter
|
||||
exclude-rules:
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test(ing)?\.go
|
||||
linters:
|
||||
- gocognit
|
||||
- gocyclo
|
||||
- errcheck
|
||||
- dupl
|
||||
- gosec
|
||||
- scopelint
|
||||
- unparam
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
- containedctx
|
||||
- forcetypeassert
|
||||
- contextcheck
|
||||
- errchkjson
|
||||
|
||||
# Ease some gocritic warnings on test files.
|
||||
- path: _test\.go
|
||||
|
@ -238,13 +159,6 @@ issues:
|
|||
linters:
|
||||
- gocritic
|
||||
|
||||
# It's idiomatic to register Kubernetes types with a package scoped
|
||||
# SchemeBuilder using an init function.
|
||||
- path: apis/
|
||||
linters:
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
|
||||
# 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.
|
||||
|
@ -276,18 +190,6 @@ issues:
|
|||
- gosec
|
||||
- gas
|
||||
|
||||
# This is about implicit memory aliasing in a range loop.
|
||||
# This is a false positive with Go v1.22 and above.
|
||||
- text: "G601:"
|
||||
linters:
|
||||
- gosec
|
||||
- gas
|
||||
|
||||
# Some k8s dependencies do not have JSON tags on all fields in structs.
|
||||
- path: k8s.io/
|
||||
linters:
|
||||
- musttag
|
||||
|
||||
# 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`.
|
||||
|
@ -303,7 +205,7 @@ issues:
|
|||
new: false
|
||||
|
||||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||
max-issues-per-linter: 0
|
||||
max-per-linter: 0
|
||||
|
||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||
max-same-issues: 0
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
# See also OWNERS.md for governance details
|
||||
|
||||
# Fallback owners
|
||||
* @crossplane/crossplane-maintainers
|
||||
* @crossplane/crossplane-maintainers @crossplane/crossplane-reviewers
|
||||
|
||||
# Governance owners - steering committee
|
||||
/README.md @crossplane/steering-committee
|
||||
|
|
153
Earthfile
153
Earthfile
|
@ -1,153 +0,0 @@
|
|||
# See https://docs.earthly.dev/docs/earthfile/features
|
||||
VERSION --try --raw-output 0.8
|
||||
|
||||
PROJECT crossplane/crossplane-runtime
|
||||
|
||||
ARG --global GO_VERSION=1.23.7
|
||||
|
||||
# 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=v1.64.8
|
||||
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
|
|
@ -0,0 +1,95 @@
|
|||
# ====================================================================================
|
||||
# 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
|
||||
GOLANGCILINT_VERSION = 1.54.2
|
||||
-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
|
||||
|
||||
|
||||
# NOTE(hasheddan): the build submodule currently overrides XDG_CACHE_HOME in
|
||||
# order to force the Helm 3 to use the .work/helm directory. This causes Go on
|
||||
# Linux machines to use that directory as the build cache as well. We should
|
||||
# adjust this behavior in the build submodule because it is also causing Linux
|
||||
# users to duplicate their build cache, but for now we just make it easier to
|
||||
# identify its location in CI so that we cache between builds.
|
||||
go.cachedir:
|
||||
@go env GOCACHE
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
|
@ -5,7 +5,7 @@ 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)
|
||||
Please see [GOVERNANCE.md](https://github.com/crossplane/crossplane/blob/masterGOVERNANCE.md)
|
||||
for governance guidelines and responsibilities for maintainers, and reviewers.
|
||||
|
||||
See [CODEOWNERS](CODEOWNERS) for automatic PR assignment.
|
||||
|
@ -14,15 +14,17 @@ See [CODEOWNERS](CODEOWNERS) for automatic PR assignment.
|
|||
## 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
|
||||
|
||||
* Bob Haddleton <bob.haddleton@nokia.com> ([bobh66](https://github.com/bobh66))
|
||||
* 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))
|
||||
* Philippe Scorsolini <philippe.scorsolini@upbound.io> ([phisco](https://github.com/phisco))
|
||||
|
||||
## Emeritus maintainers
|
||||
|
||||
|
|
12
README.md
12
README.md
|
@ -47,15 +47,15 @@ crossplane-runtime is under the Apache 2.0 license.
|
|||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fcrossplane%2Fcrossplane-runtime?ref=badge_large)
|
||||
|
||||
[developer guide]: https://github.com/crossplane/crossplane/tree/main/contributing
|
||||
[developer guide]: https://github.com/crossplane/crossplane/tree/master/contributing
|
||||
[API documentation]: https://godoc.org/github.com/crossplane/crossplane-runtime
|
||||
[contributing]: https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md
|
||||
[contributing]: https://github.com/crossplane/crossplane/blob/master/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/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
|
||||
[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
|
||||
|
|
|
@ -12,9 +12,9 @@ In order to cut a new patch release from an existing release branch `release-X.Y
|
|||
|
||||
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`.
|
||||
- Create a new release branch `release-X.Y` from `master`, using the [GitHub UI][create-branch].
|
||||
- Create and merge an empty commit to the `master` branch, if required to have it at least one commit ahead of the release branch.
|
||||
- Run the [Tag workflow][tag-workflow] on the `master` branch with the release candidate tag for the next release, 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.
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
## Reporting a Vulnerability
|
||||
|
||||
Instructions for reporting a vulnerability can be found on the
|
||||
[crossplane repository](https://github.com/crossplane/crossplane/blob/main/SECURITY.md).
|
||||
[crossplane repository](https://github.com/crossplane/crossplane/blob/master/SECURITY.md).
|
||||
|
||||
|
|
|
@ -35,12 +35,13 @@ limitations under the License.
|
|||
// (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
|
||||
//go:generate go run github.com/bufbuild/buf/cmd/buf generate
|
||||
|
||||
// Package apis contains Kubernetes API groups
|
||||
package apis
|
||||
|
||||
import (
|
||||
_ "github.com/bufbuild/buf/cmd/buf" //nolint:typecheck
|
||||
_ "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
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
version: v1
|
||||
name: buf.build/crossplane/crossplane-runtime
|
||||
breaking:
|
||||
use:
|
||||
- FILE
|
||||
lint:
|
||||
use:
|
||||
- DEFAULT
|
||||
allow_comment_ignores: true
|
|
@ -1,499 +0,0 @@
|
|||
//
|
||||
//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.34.2
|
||||
// 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"
|
||||
)
|
||||
|
||||
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
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The change log entry to send as part of this request.
|
||||
Entry *ChangeLogEntry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SendChangeLogRequest) Reset() {
|
||||
*x = SendChangeLogRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
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 protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use 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
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// 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,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *ChangeLogEntry) Reset() {
|
||||
*x = ChangeLogEntry{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
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 protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use 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
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *SendChangeLogResponse) Reset() {
|
||||
*x = SendChangeLogResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
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 protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use 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 = []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 = file_changelogs_proto_v1alpha1_changelog_proto_rawDesc
|
||||
)
|
||||
|
||||
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(file_changelogs_proto_v1alpha1_changelog_proto_rawDescData)
|
||||
})
|
||||
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
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*SendChangeLogRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ChangeLogEntry); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_changelogs_proto_v1alpha1_changelog_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*SendChangeLogResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
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: 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_rawDesc = nil
|
||||
file_changelogs_proto_v1alpha1_changelog_proto_goTypes = nil
|
||||
file_changelogs_proto_v1alpha1_changelog_proto_depIdxs = nil
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
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 {}
|
|
@ -1,125 +0,0 @@
|
|||
//
|
||||
//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",
|
||||
}
|
|
@ -34,17 +34,6 @@ const (
|
|||
// 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.
|
||||
|
@ -65,8 +54,6 @@ const (
|
|||
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 {
|
||||
// Type of this condition. At most one of each condition type may apply to
|
||||
|
@ -87,12 +74,6 @@ type Condition struct {
|
|||
// 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,
|
||||
|
@ -101,8 +82,7 @@ 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
|
||||
c.Message == other.Message
|
||||
}
|
||||
|
||||
// WithMessage returns a condition by adding the provided message to existing
|
||||
|
@ -112,23 +92,6 @@ func (c Condition) WithMessage(msg string) Condition {
|
|||
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.
|
||||
|
@ -154,7 +117,7 @@ func NewConditionedStatus(c ...Condition) *ConditionedStatus {
|
|||
}
|
||||
|
||||
// GetCondition returns the condition for the given ConditionType if exists,
|
||||
// otherwise returns nil.
|
||||
// otherwise returns nil
|
||||
func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition {
|
||||
for _, c := range s.Conditions {
|
||||
if c.Type == ct {
|
||||
|
@ -169,23 +132,23 @@ func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition {
|
|||
// 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 {
|
||||
for _, new := range c {
|
||||
exists := false
|
||||
for i, existing := range s.Conditions {
|
||||
if existing.Type != cond.Type {
|
||||
if existing.Type != new.Type {
|
||||
continue
|
||||
}
|
||||
|
||||
if existing.Equal(cond) {
|
||||
if existing.Equal(new) {
|
||||
exists = true
|
||||
continue
|
||||
}
|
||||
|
||||
s.Conditions[i] = cond
|
||||
s.Conditions[i] = new
|
||||
exists = true
|
||||
}
|
||||
if !exists {
|
||||
s.Conditions = append(s.Conditions, cond)
|
||||
s.Conditions = append(s.Conditions, new)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,25 +32,6 @@ 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()},
|
||||
|
@ -76,11 +57,6 @@ 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{
|
||||
|
@ -163,11 +139,6 @@ 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()},
|
||||
|
@ -257,64 +228,3 @@ 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
// MergeOptions Specifies merge options on a field path.
|
||||
// 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
|
||||
|
@ -30,7 +30,7 @@ type MergeOptions struct { // TODO(aru): add more options that control merging b
|
|||
AppendSlice *bool `json:"appendSlice,omitempty"`
|
||||
}
|
||||
|
||||
// MergoConfiguration the default behavior is to replace maps and slices.
|
||||
// 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 {
|
||||
|
@ -46,7 +46,7 @@ func (mo *MergeOptions) MergoConfiguration() []func(*mergo.Config) {
|
|||
return config
|
||||
}
|
||||
|
||||
// IsAppendSlice returns true if mo.AppendSlice is set to true.
|
||||
// IsAppendSlice returns true if mo.AppendSlice is set to true
|
||||
func (mo *MergeOptions) IsAppendSlice() bool {
|
||||
return mo != nil && mo.AppendSlice != nil && *mo.AppendSlice
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ func TestMergoConfiguration(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)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
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
|
||||
|
||||
// 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
|
||||
}
|
|
@ -23,23 +23,23 @@ import (
|
|||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
|
@ -226,7 +226,6 @@ 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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//go:build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2025 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.
|
||||
|
@ -262,21 +262,6 @@ func (in *MergeOptions) DeepCopy() *MergeOptions {
|
|||
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 *PluginStoreConfig) DeepCopyInto(out *PluginStoreConfig) {
|
||||
*out = *in
|
||||
|
@ -435,7 +420,6 @@ func (in *ResourceSpec) DeepCopy() *ResourceSpec {
|
|||
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.
|
||||
|
|
|
@ -12,12 +12,10 @@
|
|||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.34.2
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc (unknown)
|
||||
// source: proto/v1alpha1/ess.proto
|
||||
|
||||
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
|
@ -569,7 +567,7 @@ func file_proto_v1alpha1_ess_proto_rawDescGZIP() []byte {
|
|||
}
|
||||
|
||||
var file_proto_v1alpha1_ess_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_proto_v1alpha1_ess_proto_goTypes = []any{
|
||||
var file_proto_v1alpha1_ess_proto_goTypes = []interface{}{
|
||||
(*ConfigReference)(nil), // 0: ess.proto.v1alpha1.ConfigReference
|
||||
(*Secret)(nil), // 1: ess.proto.v1alpha1.Secret
|
||||
(*GetSecretRequest)(nil), // 2: ess.proto.v1alpha1.GetSecretRequest
|
||||
|
@ -610,7 +608,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ConfigReference); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -622,7 +620,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Secret); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -634,7 +632,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetSecretRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -646,7 +644,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetSecretResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -658,7 +656,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ApplySecretRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -670,7 +668,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ApplySecretResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -682,7 +680,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DeleteKeysRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -694,7 +692,7 @@ func file_proto_v1alpha1_ess_proto_init() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||
file_proto_v1alpha1_ess_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*DeleteKeysResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
|
|
@ -13,7 +13,6 @@ 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";
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
// - protoc (unknown)
|
||||
// source: proto/v1alpha1/ess.proto
|
||||
|
||||
// buf:lint:ignore PACKAGE_DIRECTORY_MATCH
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7da2fdeb3dc1ebbce8210a58616debe34ef0fd97
|
143
go.mod
143
go.mod
|
@ -1,85 +1,124 @@
|
|||
module github.com/crossplane/crossplane-runtime
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.23.7
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
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.19.1
|
||||
github.com/spf13/afero v1.11.0
|
||||
golang.org/x/time v0.5.0
|
||||
google.golang.org/grpc v1.65.0
|
||||
dario.cat/mergo v1.0.0
|
||||
github.com/bufbuild/buf v1.27.1
|
||||
github.com/go-logr/logr v1.2.4
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/spf13/afero v1.10.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/grpc v1.59.0
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
k8s.io/api v0.31.0
|
||||
k8s.io/apiextensions-apiserver v0.31.0
|
||||
k8s.io/apimachinery v0.31.0
|
||||
k8s.io/client-go v0.31.0
|
||||
k8s.io/component-base v0.31.0
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
|
||||
sigs.k8s.io/controller-runtime v0.19.0
|
||||
sigs.k8s.io/controller-tools v0.16.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
k8s.io/api v0.28.3
|
||||
k8s.io/apiextensions-apiserver v0.28.3
|
||||
k8s.io/apimachinery v0.28.3
|
||||
k8s.io/client-go v0.28.3
|
||||
sigs.k8s.io/controller-runtime v0.16.3
|
||||
sigs.k8s.io/controller-tools v0.13.0
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
connectrpc.com/connect v1.11.1 // indirect
|
||||
connectrpc.com/otelconnect v0.6.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
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/bufbuild/protocompile v0.6.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/docker/cli v24.0.6+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v24.0.6+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.10 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/gobuffalo/flect v1.0.2 // indirect
|
||||
github.com/gofrs/uuid/v5 v5.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-containerregistry v0.16.1 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jdx/go-netrc v1.0.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.1 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.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.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
github.com/pkg/profile v1.7.0 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/rs/cors v1.10.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cobra v1.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tetratelabs/wazero v1.5.0 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/oauth2 v0.11.0 // indirect
|
||||
golang.org/x/sync v0.4.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // 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/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/component-base v0.28.3 // indirect
|
||||
k8s.io/klog/v2 v2.100.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
)
|
||||
|
|
729
go.sum
729
go.sum
|
@ -1,75 +1,239 @@
|
|||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
connectrpc.com/connect v1.11.1 h1:dqRwblixqkVh+OFBOOL1yIf1jS/yP0MSJLijRj29bFg=
|
||||
connectrpc.com/connect v1.11.1/go.mod h1:3AGaO6RRGMx5IKFfqbe3hvK1NqLosFNP2BxDYTPmNPo=
|
||||
connectrpc.com/otelconnect v0.6.0 h1:VJAdQL9+sgdUw9+7+J+jq8pQo/h1S7tSFv2+vDcR7bU=
|
||||
connectrpc.com/otelconnect v0.6.0/go.mod h1:jdcs0uiwXQVmSMgTJ2dAaWR5VbpNd7QKNkuoH7n86RA=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/bufbuild/buf v1.27.1 h1:r8nmR+QLdpzgMr/F6+ua0awewMKGVf3uHsW0/UoUeME=
|
||||
github.com/bufbuild/buf v1.27.1/go.mod h1:BTXcNcZU8rvEZv2MdmVGpEyNgrXQ2UYO9u8H8yLmOdM=
|
||||
github.com/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY=
|
||||
github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY=
|
||||
github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
|
||||
github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
||||
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA=
|
||||
github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ=
|
||||
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
|
||||
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jdx/go-netrc v1.0.0 h1:QbLMLyCZGj0NA8glAhxUpf1zDg6cxnWgMBbjq40W0gQ=
|
||||
github.com/jdx/go-netrc v1.0.0/go.mod h1:Gh9eFQJnoTNIRHXl2j5bJXA1u84hQWJWgGh569zF3v8=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g=
|
||||
github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
|
@ -79,159 +243,474 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
|
||||
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
|
||||
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
|
||||
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k=
|
||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
|
||||
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo=
|
||||
k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE=
|
||||
k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk=
|
||||
k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk=
|
||||
k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc=
|
||||
k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||
k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8=
|
||||
k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU=
|
||||
k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
|
||||
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
|
||||
sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
|
||||
sigs.k8s.io/controller-tools v0.16.0 h1:EJPB+a5Bve861SPBPPWRbP6bbKyNxqK12oYT5zEns9s=
|
||||
sigs.k8s.io/controller-tools v0.16.0/go.mod h1:0I0xqjR65YTfoO12iR+mZR6s6UAVcUARgXRlsu0ljB0=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
|
||||
k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc=
|
||||
k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08=
|
||||
k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc=
|
||||
k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A=
|
||||
k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8=
|
||||
k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4=
|
||||
k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo=
|
||||
k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI=
|
||||
k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8=
|
||||
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
|
||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4=
|
||||
sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=
|
||||
sigs.k8s.io/controller-tools v0.13.0 h1:NfrvuZ4bxyolhDBt/rCZhDnx3M2hzlhgo5n3Iv2RykI=
|
||||
sigs.k8s.io/controller-tools v0.13.0/go.mod h1:5vw3En2NazbejQGCeWKRrE7q4P+CW8/klfVqP8QZkgA=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2025 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.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
`{{violation.rule}}`: {{violation.message}}
|
||||
|
||||
Refer to Crossplane's [coding style documentation](https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md#coding-style-and-linting) for more information.
|
||||
Refer to Crossplane's [coding style documentation](https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md#coding-style-and-linting) for more information.
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
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...)
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
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
|
||||
}
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
|
||||
// Package fake implements a fake secret store.
|
||||
//
|
||||
//nolint:musttag // We only use JSON to round-trip convert these mocks.
|
||||
package fake
|
||||
|
||||
import (
|
||||
|
@ -31,7 +29,7 @@ import (
|
|||
"github.com/crossplane/crossplane-runtime/pkg/connection/store"
|
||||
)
|
||||
|
||||
// SecretStore is a fake SecretStore.
|
||||
// SecretStore is a fake SecretStore
|
||||
type SecretStore struct {
|
||||
ReadKeyValuesFn func(ctx context.Context, n store.ScopedName, s *store.Secret) error
|
||||
WriteKeyValuesFn func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error)
|
||||
|
@ -54,14 +52,14 @@ func (ss *SecretStore) DeleteKeyValues(ctx context.Context, s *store.Secret, do
|
|||
}
|
||||
|
||||
// StoreConfig is a mock implementation of the StoreConfig interface.
|
||||
type StoreConfig struct {
|
||||
type StoreConfig struct { //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
metav1.ObjectMeta
|
||||
|
||||
Config v1.SecretStoreConfig
|
||||
v1.ConditionedStatus
|
||||
}
|
||||
|
||||
// GetStoreConfig returns SecretStoreConfig.
|
||||
// GetStoreConfig returns SecretStoreConfig
|
||||
func (s *StoreConfig) GetStoreConfig() v1.SecretStoreConfig {
|
||||
return s.Config
|
||||
}
|
||||
|
@ -71,7 +69,7 @@ func (s *StoreConfig) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (s *StoreConfig) DeepCopyObject() runtime.Object {
|
||||
out := &StoreConfig{}
|
||||
j, err := json.Marshal(s)
|
||||
|
|
|
@ -79,7 +79,6 @@ type DetailsManager struct {
|
|||
// NewDetailsManager returns a new connection DetailsManager.
|
||||
func NewDetailsManager(c client.Client, of schema.GroupVersionKind, o ...DetailsManagerOption) *DetailsManager {
|
||||
nc := func() StoreConfig {
|
||||
//nolint:forcetypeassert // If the supplied type isn't a StoreConfig it's a programming error. We want to panic.
|
||||
return resource.MustCreateObject(of, c.Scheme()).(StoreConfig)
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ func TestManagerConnectStore(t *testing.T) {
|
|||
reason: "We should return a proper error if referenced StoreConfig does not exist.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, _ client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, key.Name)
|
||||
},
|
||||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
|
@ -94,13 +94,13 @@ func TestManagerConnectStore(t *testing.T) {
|
|||
reason: "We should return any error encountered while building the Store.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{}
|
||||
return nil
|
||||
},
|
||||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: func(_ context.Context, _ client.Client, _ *tls.Config, _ v1.SecretStoreConfig) (Store, error) {
|
||||
sb: func(ctx context.Context, local client.Client, tCfg *tls.Config, cfg v1.SecretStoreConfig) (Store, error) {
|
||||
return nil, errors.New(errBuildStore)
|
||||
},
|
||||
p: &v1.PublishConnectionDetailsTo{
|
||||
|
@ -117,7 +117,7 @@ func TestManagerConnectStore(t *testing.T) {
|
|||
reason: "We should not return an error when connected successfully.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -189,13 +189,13 @@ func TestManagerPublishConnection(t *testing.T) {
|
|||
reason: "We should return any error encountered while connecting to Store.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, _ client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, key.Name)
|
||||
},
|
||||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
}),
|
||||
|
@ -215,7 +215,7 @@ func TestManagerPublishConnection(t *testing.T) {
|
|||
reason: "We should return a proper error when publish to secret store failed.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -229,7 +229,7 @@ func TestManagerPublishConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return false, errBoom
|
||||
},
|
||||
}),
|
||||
|
@ -249,7 +249,7 @@ func TestManagerPublishConnection(t *testing.T) {
|
|||
reason: "We should return no error when published successfully.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -263,7 +263,7 @@ func TestManagerPublishConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
WriteKeyValuesFn: func(_ context.Context, s *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
if diff := cmp.Diff(testUID, s.Metadata.GetOwnerUID()); diff != "" {
|
||||
t.Errorf("\nReason: %s\nm.publishConnection(...): -want ownerUID, +got ownerUID:\n%s", testUID, diff)
|
||||
}
|
||||
|
@ -336,13 +336,13 @@ func TestManagerUnpublishConnection(t *testing.T) {
|
|||
reason: "We should return any error encountered while connecting to Store.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, _ client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, key.Name)
|
||||
},
|
||||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
}),
|
||||
|
@ -362,7 +362,7 @@ func TestManagerUnpublishConnection(t *testing.T) {
|
|||
reason: "We should return a proper error when delete from secret store failed.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -376,7 +376,7 @@ func TestManagerUnpublishConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
DeleteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.DeleteOption) error {
|
||||
DeleteKeyValuesFn: func(ctx context.Context, s *store.Secret, do ...store.DeleteOption) error {
|
||||
return errBoom
|
||||
},
|
||||
}),
|
||||
|
@ -396,7 +396,7 @@ func TestManagerUnpublishConnection(t *testing.T) {
|
|||
reason: "We should return a proper error when attempted to unpublish a secret that is not owned.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -443,7 +443,7 @@ func TestManagerUnpublishConnection(t *testing.T) {
|
|||
reason: "We should return no error when unpublished successfully.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -533,13 +533,13 @@ func TestManagerFetchConnection(t *testing.T) {
|
|||
reason: "We should return any error encountered while connecting to Store.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, _ client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, key.Name)
|
||||
},
|
||||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
}),
|
||||
|
@ -559,7 +559,7 @@ func TestManagerFetchConnection(t *testing.T) {
|
|||
reason: "We should return a proper error when fetch from secret store failed.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -573,7 +573,7 @@ func TestManagerFetchConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, _ *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
return errBoom
|
||||
},
|
||||
}),
|
||||
|
@ -593,7 +593,7 @@ func TestManagerFetchConnection(t *testing.T) {
|
|||
reason: "We should return no error when fetched successfully.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -607,7 +607,7 @@ func TestManagerFetchConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Data = store.KeyValues{
|
||||
"key1": []byte("val1"),
|
||||
}
|
||||
|
@ -693,13 +693,13 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return any error encountered while connecting to Source Store.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, _ client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, key.Name)
|
||||
},
|
||||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
}),
|
||||
|
@ -720,7 +720,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return a proper error when fetch from secret store failed.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -734,7 +734,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, _ *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
return errBoom
|
||||
},
|
||||
}),
|
||||
|
@ -773,7 +773,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{}
|
||||
return nil
|
||||
},
|
||||
|
@ -823,7 +823,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: "00000000-1111-2222-3333-444444444444",
|
||||
|
@ -877,7 +877,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -913,7 +913,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return any error encountered while publishing to Destination Store.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -927,7 +927,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -935,7 +935,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
}
|
||||
return nil
|
||||
},
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return false, errBoom
|
||||
},
|
||||
}),
|
||||
|
@ -965,7 +965,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return a proper error if destination secret cannot be owned by destination resource.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -979,7 +979,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -989,7 +989,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
},
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
for _, o := range wo {
|
||||
if err := o(ctx, &store.Secret{
|
||||
if err := o(context.Background(), &store.Secret{
|
||||
Metadata: &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: "00000000-1111-2222-3333-444444444444",
|
||||
|
@ -1031,7 +1031,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return no error when propagated successfully.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -1045,7 +1045,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -1053,7 +1053,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
}
|
||||
return nil
|
||||
},
|
||||
WriteKeyValuesFn: func(_ context.Context, _ *store.Secret, _ ...store.WriteOption) (bool, error) {
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
}),
|
||||
|
@ -1083,7 +1083,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return a proper error when attempted to update an unowned secret.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -1097,7 +1097,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -1107,7 +1107,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
},
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
for _, o := range wo {
|
||||
if err := o(ctx, &store.Secret{
|
||||
if err := o(context.Background(), &store.Secret{
|
||||
Data: map[string][]byte{
|
||||
"some-key": []byte("some-val"),
|
||||
},
|
||||
|
@ -1145,7 +1145,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
reason: "We should return no error when propagated successfully by updating an already owned secret.",
|
||||
args: args{
|
||||
c: &test.MockClient{
|
||||
MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
*obj.(*fake.StoreConfig) = fake.StoreConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fakeConfig,
|
||||
|
@ -1159,7 +1159,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
MockScheme: test.NewMockSchemeFn(resourcefake.SchemeWith(&fake.StoreConfig{})),
|
||||
},
|
||||
sb: fakeStoreBuilderFn(fake.SecretStore{
|
||||
ReadKeyValuesFn: func(_ context.Context, _ store.ScopedName, s *store.Secret) error {
|
||||
ReadKeyValuesFn: func(ctx context.Context, n store.ScopedName, s *store.Secret) error {
|
||||
s.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -1169,7 +1169,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
},
|
||||
WriteKeyValuesFn: func(ctx context.Context, s *store.Secret, wo ...store.WriteOption) (bool, error) {
|
||||
for _, o := range wo {
|
||||
if err := o(ctx, &store.Secret{
|
||||
if err := o(context.Background(), &store.Secret{
|
||||
Metadata: &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
v1.LabelKeyOwnerUID: testUID,
|
||||
|
@ -1227,7 +1227,7 @@ func TestManagerPropagateConnection(t *testing.T) {
|
|||
}
|
||||
|
||||
func fakeStoreBuilderFn(ss fake.SecretStore) StoreBuilderFn {
|
||||
return func(_ context.Context, _ client.Client, _ *tls.Config, cfg v1.SecretStoreConfig) (Store, error) {
|
||||
return func(_ context.Context, _ client.Client, tcfg *tls.Config, cfg v1.SecretStoreConfig) (Store, error) {
|
||||
if *cfg.Type == fakeStore {
|
||||
return &ss, nil
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ func (ss *SecretStore) WriteKeyValues(ctx context.Context, s *store.Secret, wo .
|
|||
ao = append(ao, resource.AllowUpdateIf(func(current, desired runtime.Object) bool {
|
||||
// We consider the update to be a no-op and don't allow it if the
|
||||
// current and existing secret data are identical.
|
||||
return !cmp.Equal(current.(*corev1.Secret).Data, desired.(*corev1.Secret).Data, cmpopts.EquateEmpty()) //nolint:forcetypeassert // Will always be a secret.
|
||||
return !cmp.Equal(current.(*corev1.Secret).Data, desired.(*corev1.Secret).Data, cmpopts.EquateEmpty())
|
||||
}))
|
||||
|
||||
err := ss.client.Apply(ctx, ks, ao...)
|
||||
|
@ -197,8 +197,8 @@ func applyOptions(wo ...store.WriteOption) []resource.ApplyOption {
|
|||
for i := range wo {
|
||||
o := wo[i]
|
||||
ao[i] = func(ctx context.Context, current, desired runtime.Object) error {
|
||||
currentSecret := current.(*corev1.Secret) //nolint:forcetypeassert // Will always be a secret.
|
||||
desiredSecret := desired.(*corev1.Secret) //nolint:forcetypeassert // Will always be a secret.
|
||||
currentSecret := current.(*corev1.Secret)
|
||||
desiredSecret := desired.(*corev1.Secret)
|
||||
|
||||
cs := &store.Secret{
|
||||
ScopedName: store.ScopedName{
|
||||
|
|
|
@ -102,7 +102,7 @@ func TestSecretStoreReadKeyValues(t *testing.T) {
|
|||
args: args{
|
||||
client: resource.ClientApplicator{
|
||||
Client: &test.MockClient{
|
||||
MockGet: func(_ context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
if key.Name != fakeSecretName || key.Namespace != fakeSecretNamespace {
|
||||
return errors.New("unexpected secret name or namespace to get the secret")
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
|
|||
reason: "Should return a proper error when cannot apply.",
|
||||
args: args{
|
||||
client: resource.ClientApplicator{
|
||||
Applicator: resource.ApplyFn(func(_ context.Context, _ client.Object, _ ...resource.ApplyOption) error {
|
||||
Applicator: resource.ApplyFn(func(ctx context.Context, obj client.Object, option ...resource.ApplyOption) error {
|
||||
return errBoom
|
||||
}),
|
||||
},
|
||||
|
@ -216,7 +216,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
|
|||
Data: store.KeyValues(fakeKV()),
|
||||
},
|
||||
wo: []store.WriteOption{
|
||||
func(_ context.Context, _, _ *store.Secret) error {
|
||||
func(ctx context.Context, current, desired *store.Secret) error {
|
||||
return errBoom
|
||||
},
|
||||
},
|
||||
|
@ -246,7 +246,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
|
|||
Data: store.KeyValues(fakeKV()),
|
||||
},
|
||||
wo: []store.WriteOption{
|
||||
func(_ context.Context, _, desired *store.Secret) error {
|
||||
func(ctx context.Context, current, desired *store.Secret) error {
|
||||
desired.Data["customkey"] = []byte("customval")
|
||||
desired.Metadata = &v1.ConnectionSecretMetadata{
|
||||
Labels: map[string]string{
|
||||
|
@ -346,7 +346,7 @@ func TestSecretStoreWriteKeyValues(t *testing.T) {
|
|||
"existing-key": []byte("new-value"),
|
||||
}),
|
||||
},
|
||||
wo: []store.WriteOption{func(_ context.Context, current, _ *store.Secret) error {
|
||||
wo: []store.WriteOption{func(ctx context.Context, current, desired *store.Secret) error {
|
||||
if current.Metadata == nil || current.Metadata.GetOwnerUID() != fakeOwnerID {
|
||||
return errors.Errorf("secret not owned by %s", fakeOwnerID)
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
|
|||
*obj.(*corev1.Secret) = *fakeConnectionSecret(withData(fakeKV()))
|
||||
return nil
|
||||
}),
|
||||
MockUpdate: func(_ context.Context, obj client.Object, _ ...client.UpdateOption) error {
|
||||
MockUpdate: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
|
||||
if diff := cmp.Diff(fakeConnectionSecret(withData(map[string][]byte{"key3": []byte("value3")})), obj.(*corev1.Secret)); diff != "" {
|
||||
t.Errorf("r: -want, +got:\n%s", diff)
|
||||
}
|
||||
|
@ -575,7 +575,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
|
|||
args: args{
|
||||
client: resource.ClientApplicator{
|
||||
Client: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(_ client.Object) error {
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, "")
|
||||
}),
|
||||
},
|
||||
|
@ -600,7 +600,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
|
|||
*obj.(*corev1.Secret) = *fakeConnectionSecret(withData(fakeKV()))
|
||||
return nil
|
||||
}),
|
||||
MockDelete: func(_ context.Context, _ client.Object, _ ...client.DeleteOption) error {
|
||||
MockDelete: func(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -612,7 +612,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
|
|||
},
|
||||
},
|
||||
do: []store.DeleteOption{
|
||||
func(_ context.Context, _ *store.Secret) error {
|
||||
func(ctx context.Context, secret *store.Secret) error {
|
||||
return errBoom
|
||||
},
|
||||
},
|
||||
|
@ -630,7 +630,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
|
|||
*obj.(*corev1.Secret) = *fakeConnectionSecret(withData(fakeKV()))
|
||||
return nil
|
||||
}),
|
||||
MockDelete: func(_ context.Context, _ client.Object, _ ...client.DeleteOption) error {
|
||||
MockDelete: func(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -642,7 +642,7 @@ func TestSecretStoreDeleteKeyValues(t *testing.T) {
|
|||
},
|
||||
},
|
||||
do: []store.DeleteOption{
|
||||
func(_ context.Context, _ *store.Secret) error {
|
||||
func(ctx context.Context, secret *store.Secret) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -698,7 +698,7 @@ func TestNewSecretStore(t *testing.T) {
|
|||
args: args{
|
||||
client: resource.ClientApplicator{
|
||||
Client: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(_ client.Object) error {
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
return kerrors.NewNotFound(schema.GroupResource{}, "kube-conn")
|
||||
}),
|
||||
},
|
||||
|
|
|
@ -53,7 +53,7 @@ type SecretStore struct {
|
|||
// NewSecretStore returns a new External SecretStore.
|
||||
func NewSecretStore(_ context.Context, kube client.Client, tcfg *tls.Config, cfg v1.SecretStoreConfig) (*SecretStore, error) {
|
||||
creds := credentials.NewTLS(tcfg)
|
||||
conn, err := grpc.NewClient(cfg.Plugin.Endpoint, grpc.WithTransportCredentials(creds))
|
||||
conn, err := grpc.Dial(cfg.Plugin.Endpoint, grpc.WithTransportCredentials(creds))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errFmtCannotDial, cfg.Plugin.Endpoint)
|
||||
}
|
||||
|
@ -74,23 +74,14 @@ func (ss *SecretStore) ReadKeyValues(ctx context.Context, n store.ScopedName, s
|
|||
}
|
||||
|
||||
s.ScopedName = n
|
||||
|
||||
respSecret := resp.GetSecret()
|
||||
if respSecret == nil {
|
||||
return nil
|
||||
s.Data = make(map[string][]byte, len(resp.Secret.Data))
|
||||
for d := range resp.Secret.Data {
|
||||
s.Data[d] = resp.Secret.Data[d]
|
||||
}
|
||||
|
||||
respSecretData := respSecret.GetData()
|
||||
s.Data = make(map[string][]byte, len(respSecretData))
|
||||
for d := range respSecretData {
|
||||
s.Data[d] = respSecretData[d]
|
||||
}
|
||||
|
||||
respSecretMetadata := respSecret.GetMetadata()
|
||||
if len(respSecretMetadata) != 0 {
|
||||
if resp.Secret != nil && len(resp.Secret.Metadata) != 0 {
|
||||
s.Metadata = new(v1.ConnectionSecretMetadata)
|
||||
s.Metadata.Labels = make(map[string]string, len(respSecretMetadata))
|
||||
for k, v := range respSecretMetadata {
|
||||
s.Metadata.Labels = make(map[string]string, len(resp.Secret.Metadata))
|
||||
for k, v := range resp.Secret.Metadata {
|
||||
s.Metadata.Labels[k] = v
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +110,7 @@ func (ss *SecretStore) WriteKeyValues(ctx context.Context, s *store.Secret, _ ..
|
|||
return false, errors.Wrap(err, errApply)
|
||||
}
|
||||
|
||||
return resp.GetChanged(), nil
|
||||
return resp.Changed, nil
|
||||
}
|
||||
|
||||
// DeleteKeyValues delete key value pairs from a given Secret.
|
||||
|
|
|
@ -37,7 +37,9 @@ const (
|
|||
secretName = "ess-test-secret"
|
||||
)
|
||||
|
||||
var errBoom = errors.New("boom")
|
||||
var (
|
||||
errBoom = errors.New("boom")
|
||||
)
|
||||
|
||||
func TestReadKeyValues(t *testing.T) {
|
||||
type args struct {
|
||||
|
@ -57,7 +59,7 @@ func TestReadKeyValues(t *testing.T) {
|
|||
reason: "Should return a proper error if secret cannot be obtained",
|
||||
args: args{
|
||||
client: &fake.ExternalSecretStorePluginServiceClient{
|
||||
GetSecretFn: func(_ context.Context, _ *ess.GetSecretRequest, _ ...grpc.CallOption) (*ess.GetSecretResponse, error) {
|
||||
GetSecretFn: func(ctx context.Context, req *ess.GetSecretRequest, opts ...grpc.CallOption) (*ess.GetSecretResponse, error) {
|
||||
return nil, errBoom
|
||||
},
|
||||
},
|
||||
|
@ -75,12 +77,12 @@ func TestReadKeyValues(t *testing.T) {
|
|||
Scope: parentPath,
|
||||
},
|
||||
client: &fake.ExternalSecretStorePluginServiceClient{
|
||||
GetSecretFn: func(_ context.Context, req *ess.GetSecretRequest, _ ...grpc.CallOption) (*ess.GetSecretResponse, error) {
|
||||
if diff := cmp.Diff(filepath.Join(parentPath, secretName), req.GetSecret().GetScopedName()); diff != "" {
|
||||
GetSecretFn: func(ctx context.Context, req *ess.GetSecretRequest, opts ...grpc.CallOption) (*ess.GetSecretResponse, error) {
|
||||
if diff := cmp.Diff(filepath.Join(parentPath, secretName), req.Secret.ScopedName); diff != "" {
|
||||
t.Errorf("r: -want, +got:\n%s", diff)
|
||||
}
|
||||
sec := &ess.Secret{
|
||||
ScopedName: req.GetSecret().GetScopedName(),
|
||||
ScopedName: req.Secret.ScopedName,
|
||||
Data: map[string][]byte{
|
||||
"data1": []byte("val1"),
|
||||
"data2": []byte("val2"),
|
||||
|
@ -162,7 +164,7 @@ func TestWriteKeyValues(t *testing.T) {
|
|||
reason: "Should return a proper error if secret cannot be applied",
|
||||
args: args{
|
||||
client: &fake.ExternalSecretStorePluginServiceClient{
|
||||
ApplySecretFn: func(_ context.Context, _ *ess.ApplySecretRequest, _ ...grpc.CallOption) (*ess.ApplySecretResponse, error) {
|
||||
ApplySecretFn: func(ctx context.Context, req *ess.ApplySecretRequest, opts ...grpc.CallOption) (*ess.ApplySecretResponse, error) {
|
||||
return nil, errBoom
|
||||
},
|
||||
},
|
||||
|
@ -176,7 +178,7 @@ func TestWriteKeyValues(t *testing.T) {
|
|||
reason: "Should return isChanged true",
|
||||
args: args{
|
||||
client: &fake.ExternalSecretStorePluginServiceClient{
|
||||
ApplySecretFn: func(_ context.Context, _ *ess.ApplySecretRequest, _ ...grpc.CallOption) (*ess.ApplySecretResponse, error) {
|
||||
ApplySecretFn: func(ctx context.Context, req *ess.ApplySecretRequest, opts ...grpc.CallOption) (*ess.ApplySecretResponse, error) {
|
||||
resp := &ess.ApplySecretResponse{
|
||||
Changed: true,
|
||||
}
|
||||
|
@ -233,10 +235,9 @@ func TestDeleteKeyValues(t *testing.T) {
|
|||
reason: "Should return a proper error if key values cannot be deleted",
|
||||
args: args{
|
||||
client: &fake.ExternalSecretStorePluginServiceClient{
|
||||
DeleteKeysFn: func(_ context.Context, _ *ess.DeleteKeysRequest, _ ...grpc.CallOption) (*ess.DeleteKeysResponse, error) {
|
||||
DeleteKeysFn: func(ctx context.Context, req *ess.DeleteKeysRequest, opts ...grpc.CallOption) (*ess.DeleteKeysResponse, error) {
|
||||
return nil, errBoom
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(errBoom, errDelete),
|
||||
|
@ -246,7 +247,7 @@ func TestDeleteKeyValues(t *testing.T) {
|
|||
reason: "Should not return error",
|
||||
args: args{
|
||||
client: &fake.ExternalSecretStorePluginServiceClient{
|
||||
DeleteKeysFn: func(_ context.Context, _ *ess.DeleteKeysRequest, _ ...grpc.CallOption) (*ess.DeleteKeysResponse, error) {
|
||||
DeleteKeysFn: func(ctx context.Context, req *ess.DeleteKeysRequest, opts ...grpc.CallOption) (*ess.DeleteKeysResponse, error) {
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
controllerruntime "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
)
|
||||
|
||||
// GVKRoutedCache is a cache that routes requests by GVK to other caches.
|
||||
type GVKRoutedCache struct {
|
||||
scheme *runtime.Scheme
|
||||
|
||||
fallback cache.Cache
|
||||
|
||||
lock sync.RWMutex
|
||||
delegates map[schema.GroupVersionKind]cache.Cache
|
||||
}
|
||||
|
||||
// NewGVKRoutedCache returns a new routed cache.
|
||||
func NewGVKRoutedCache(scheme *runtime.Scheme, fallback cache.Cache) *GVKRoutedCache {
|
||||
return &GVKRoutedCache{
|
||||
scheme: scheme,
|
||||
fallback: fallback,
|
||||
delegates: make(map[schema.GroupVersionKind]cache.Cache),
|
||||
}
|
||||
}
|
||||
|
||||
var _ cache.Cache = &GVKRoutedCache{}
|
||||
|
||||
// AddDelegate adds a delegated cache for a given GVK.
|
||||
func (c *GVKRoutedCache) AddDelegate(gvk schema.GroupVersionKind, delegate cache.Cache) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
c.delegates[gvk] = delegate
|
||||
}
|
||||
|
||||
// RemoveDelegate removes a delegated cache for a given GVK.
|
||||
func (c *GVKRoutedCache) RemoveDelegate(gvk schema.GroupVersionKind) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
delete(c.delegates, gvk)
|
||||
}
|
||||
|
||||
// Get retrieves an object for a given ObjectKey backed by a cache.
|
||||
func (c *GVKRoutedCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to get GVK for type %T: %w", obj, err)
|
||||
}
|
||||
|
||||
c.lock.RLock()
|
||||
delegate, ok := c.delegates[gvk]
|
||||
c.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.Get(ctx, key, obj, opts...)
|
||||
}
|
||||
|
||||
return c.fallback.Get(ctx, key, obj, opts...)
|
||||
}
|
||||
|
||||
// List lists objects for a given ObjectList backed by a cache.
|
||||
func (c *GVKRoutedCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
gvk, err := apiutil.GVKForObject(list, c.scheme)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to get GVK for type %T: %w", list, err)
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(gvk.Kind, "List") {
|
||||
// following controller-runtime here which does not support non
|
||||
// <Kind>List types.
|
||||
return errors.Errorf("non-list type %T (kind %q) passed as output", list, gvk)
|
||||
}
|
||||
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
||||
|
||||
c.lock.RLock()
|
||||
delegate, ok := c.delegates[gvk]
|
||||
c.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.List(ctx, list, opts...)
|
||||
}
|
||||
|
||||
return c.fallback.List(ctx, list, opts...)
|
||||
}
|
||||
|
||||
// GetInformer returns an informer for the given object.
|
||||
func (c *GVKRoutedCache) GetInformer(ctx context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error) {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to get GVK for type %T: %w", obj, err)
|
||||
}
|
||||
|
||||
c.lock.RLock()
|
||||
delegate, ok := c.delegates[gvk]
|
||||
c.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.GetInformer(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
return c.fallback.GetInformer(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// GetInformerForKind returns an informer for the given GVK.
|
||||
func (c *GVKRoutedCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...cache.InformerGetOption) (cache.Informer, error) {
|
||||
c.lock.RLock()
|
||||
delegate, ok := c.delegates[gvk]
|
||||
c.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.GetInformerForKind(ctx, gvk, opts...)
|
||||
}
|
||||
|
||||
return c.fallback.GetInformerForKind(ctx, gvk, opts...)
|
||||
}
|
||||
|
||||
// Start for a GVKRoutedCache is a no-op. Start must be called for each delegate.
|
||||
func (c *GVKRoutedCache) Start(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForCacheSync for a GVKRoutedCache waits for all delegates to sync, and
|
||||
// returns false if any of them fails to sync.
|
||||
func (c *GVKRoutedCache) WaitForCacheSync(ctx context.Context) bool {
|
||||
c.lock.RLock()
|
||||
syncedCh := make(chan bool, len(c.delegates)+1)
|
||||
cas := make([]cache.Cache, 0, len(c.delegates))
|
||||
for _, ca := range c.delegates {
|
||||
cas = append(cas, ca)
|
||||
}
|
||||
cas = append(cas, c.fallback)
|
||||
c.lock.RUnlock()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
ctx, cancelFn := context.WithCancel(ctx)
|
||||
|
||||
for _, ca := range cas {
|
||||
wg.Add(1)
|
||||
go func(ca cache.Cache) {
|
||||
defer wg.Done()
|
||||
synced := ca.WaitForCacheSync(ctx)
|
||||
if !synced {
|
||||
// first unsynced cache breaks the whole wait
|
||||
cancelFn()
|
||||
}
|
||||
syncedCh <- synced
|
||||
}(ca)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(syncedCh)
|
||||
cancelFn()
|
||||
|
||||
// any not synced?
|
||||
for synced := range syncedCh {
|
||||
if !synced {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IndexField adds an index with the given field name on the given object type
|
||||
// by using the given function to extract the value for that field.
|
||||
func (c *GVKRoutedCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to get GVK for type %T: %w", obj, err)
|
||||
}
|
||||
|
||||
c.lock.RLock()
|
||||
delegate, ok := c.delegates[gvk]
|
||||
c.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.IndexField(ctx, obj, field, extractValue)
|
||||
}
|
||||
|
||||
return c.fallback.IndexField(ctx, obj, field, extractValue)
|
||||
}
|
||||
|
||||
// cachedRoutedClient wraps a client and routes read requests by GVK to a cache.
|
||||
type cachedRoutedClient struct {
|
||||
client.Client
|
||||
|
||||
scheme *runtime.Scheme
|
||||
cache *GVKRoutedCache
|
||||
}
|
||||
|
||||
func (c *cachedRoutedClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to get GVK for type %T: %w", obj, err)
|
||||
}
|
||||
|
||||
c.cache.lock.RLock()
|
||||
delegate, ok := c.cache.delegates[gvk]
|
||||
c.cache.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.Get(ctx, key, obj, opts...)
|
||||
}
|
||||
|
||||
return c.Client.Get(ctx, key, obj, opts...)
|
||||
}
|
||||
|
||||
func (c *cachedRoutedClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
gvk, err := apiutil.GVKForObject(list, c.scheme)
|
||||
if err != nil {
|
||||
return errors.Errorf("failed to get GVK for type %T: %w", list, err)
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(gvk.Kind, "List") {
|
||||
// following controller-runtime here which does not support non
|
||||
// <Kind>List types.
|
||||
return errors.Errorf("non-list type %T (kind %q) passed as output", list, gvk)
|
||||
}
|
||||
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
||||
|
||||
c.cache.lock.RLock()
|
||||
delegate, ok := c.cache.delegates[gvk]
|
||||
c.cache.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
return delegate.List(ctx, list, opts...)
|
||||
}
|
||||
|
||||
return c.Client.List(ctx, list, opts...)
|
||||
}
|
||||
|
||||
// WithGVKRoutedCache returns a manager backed by a GVKRoutedCache. The client
|
||||
// returned by the manager will route read requests to cached GVKs.
|
||||
func WithGVKRoutedCache(c *GVKRoutedCache, mgr controllerruntime.Manager) controllerruntime.Manager {
|
||||
return &routedManager{
|
||||
Manager: mgr,
|
||||
client: &cachedRoutedClient{
|
||||
Client: mgr.GetClient(),
|
||||
scheme: mgr.GetScheme(),
|
||||
cache: c,
|
||||
},
|
||||
cache: c,
|
||||
}
|
||||
}
|
||||
|
||||
type routedManager struct {
|
||||
controllerruntime.Manager
|
||||
|
||||
client client.Client
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func (m *routedManager) GetClient() client.Client {
|
||||
return m.client
|
||||
}
|
||||
|
||||
func (m *routedManager) GetCache() cache.Cache {
|
||||
return m.cache
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
"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/client/apiutil"
|
||||
"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/errors"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
// one of the two:
|
||||
kind client.Object
|
||||
customSource source.Source
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
// TriggeredBy returns a custom watch for secondary resources triggering the
|
||||
// controller. source.Kind can be used to create a source for a secondary cache.
|
||||
// Events will be handled by the supplied EventHandler, and may be filtered by
|
||||
// the supplied predicates.
|
||||
func TriggeredBy(source source.Source, h handler.EventHandler, p ...predicate.Predicate) Watch {
|
||||
return Watch{customSource: source, 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 {
|
||||
c, err := e.Create(name, o, w...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Start(context.Background())
|
||||
}
|
||||
|
||||
// NamedController is a controller that's not yet started. It gives access to
|
||||
// the underlying cache, which may be used e.g. to add indexes.
|
||||
type NamedController interface {
|
||||
Start(ctx context.Context) error
|
||||
GetCache() cache.Cache
|
||||
}
|
||||
|
||||
type namedController struct {
|
||||
name string
|
||||
e *Engine
|
||||
ca cache.Cache
|
||||
ctrl controller.Controller
|
||||
}
|
||||
|
||||
// Create the named controller. Each controller gets its own cache
|
||||
// whose lifecycle is coupled to the controller. The controller is created with
|
||||
// the supplied options, and configured with the supplied watches. It is not
|
||||
// started yet.
|
||||
func (e *Engine) Create(name string, o controller.Options, w ...Watch) (NamedController, error) {
|
||||
// Each controller gets its own cache for the GVKs it owns. This cache is
|
||||
// wrapped by a GVKRoutedCache that routes requests to other GVKs to the
|
||||
// manager's cache. This way we can share informers for composed resources
|
||||
// (that's where this is primarily used) with other controllers, but get
|
||||
// control about the lifecycle of the owned GVKs' informers.
|
||||
ca, err := e.newCache(e.mgr.GetConfig(), cache.Options{Scheme: e.mgr.GetScheme(), Mapper: e.mgr.GetRESTMapper()})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errCreateCache)
|
||||
}
|
||||
|
||||
// Wrap the existing manager to use our cache for the GVKs of this controller.
|
||||
rc := NewGVKRoutedCache(e.mgr.GetScheme(), e.mgr.GetCache())
|
||||
rm := &routedManager{
|
||||
Manager: e.mgr,
|
||||
client: &cachedRoutedClient{
|
||||
Client: e.mgr.GetClient(),
|
||||
scheme: e.mgr.GetScheme(),
|
||||
cache: rc,
|
||||
},
|
||||
cache: rc,
|
||||
}
|
||||
|
||||
ctrl, err := e.newCtrl(name, rm, o)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errCreateController)
|
||||
}
|
||||
|
||||
for _, wt := range w {
|
||||
if wt.customSource != nil {
|
||||
if err := ctrl.Watch(wt.customSource, wt.handler, wt.predicates...); err != nil {
|
||||
return nil, errors.Wrap(err, errWatch)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// route cache and client (read) requests to our cache for this GVK.
|
||||
gvk, err := apiutil.GVKForObject(wt.kind, e.mgr.GetScheme())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get GVK for type %T", wt.kind)
|
||||
}
|
||||
rc.AddDelegate(gvk, ca)
|
||||
|
||||
if err := ctrl.Watch(source.Kind(ca, wt.kind), wt.handler, wt.predicates...); err != nil {
|
||||
return nil, errors.Wrap(err, errWatch)
|
||||
}
|
||||
}
|
||||
|
||||
return &namedController{name: name, e: e, ca: ca, ctrl: ctrl}, nil
|
||||
}
|
||||
|
||||
// Start the named controller. Start does not block.
|
||||
func (c *namedController) Start(ctx context.Context) error {
|
||||
if c.e.IsRunning(c.name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, stop := context.WithCancel(ctx)
|
||||
c.e.mx.Lock()
|
||||
c.e.started[c.name] = stop
|
||||
c.e.errors[c.name] = nil
|
||||
c.e.mx.Unlock()
|
||||
|
||||
go func() {
|
||||
<-c.e.mgr.Elected()
|
||||
c.e.done(c.name, errors.Wrap(c.ca.Start(ctx), errCrashCache))
|
||||
}()
|
||||
go func() {
|
||||
<-c.e.mgr.Elected()
|
||||
c.e.done(c.name, errors.Wrap(c.ctrl.Start(ctx), errCrashController))
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCache returns the cache used by the named controller.
|
||||
func (c *namedController) GetCache() cache.Cache {
|
||||
return c.ca
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
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"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"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/errors"
|
||||
"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{
|
||||
Scheme: runtime.NewScheme(),
|
||||
Cache: &MockCache{},
|
||||
},
|
||||
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{
|
||||
Scheme: runtime.NewScheme(),
|
||||
Cache: &MockCache{},
|
||||
},
|
||||
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(&unstructured.Unstructured{
|
||||
Object: map[string]interface{}{"apiVersion": "example.org/v1", "kind": "Thing"},
|
||||
}, nil)},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(errBoom, errWatch),
|
||||
},
|
||||
},
|
||||
"SchemeError": {
|
||||
reason: "Passing an object of unknown GVK",
|
||||
e: NewEngine(
|
||||
&fake.Manager{
|
||||
Scheme: runtime.NewScheme(),
|
||||
Cache: &MockCache{},
|
||||
},
|
||||
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(&unstructured.Unstructured{}, nil)},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(runtime.NewMissingKindErr("unstructured object has no kind"), "failed to get GVK for type *unstructured.Unstructured"),
|
||||
},
|
||||
},
|
||||
"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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -14,20 +14,18 @@ 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"
|
||||
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"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
|
||||
|
@ -49,7 +47,7 @@ type Options struct {
|
|||
|
||||
// The GlobalRateLimiter used by this controller manager. The rate of
|
||||
// reconciles across all controllers will be subject to this limit.
|
||||
GlobalRateLimiter ratelimiter.RateLimiter
|
||||
GlobalRateLimiter workqueue.RateLimiter
|
||||
|
||||
// PollInterval at which each controller should speculatively poll to
|
||||
// determine whether it has work to do.
|
||||
|
@ -63,12 +61,6 @@ type Options struct {
|
|||
|
||||
// ESSOptions for External Secret Stores.
|
||||
ESSOptions *ESSOptions
|
||||
|
||||
// MetricOptions for recording metrics.
|
||||
MetricOptions *MetricOptions
|
||||
|
||||
// ChangeLogOptions for recording change logs.
|
||||
ChangeLogOptions *ChangeLogOptions
|
||||
}
|
||||
|
||||
// ForControllerRuntime extracts options for controller-runtime.
|
||||
|
@ -87,21 +79,3 @@ 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
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ func Wrap(err error, message string) error {
|
|||
return WithMessage(err, message)
|
||||
}
|
||||
|
||||
// Wrapf is an alias for WithMessagef.
|
||||
// Wrapf is an alias for WithMessagef
|
||||
func Wrapf(err error, format string, args ...any) error {
|
||||
return WithMessagef(err, format, args...)
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ func Cause(err error) error {
|
|||
}
|
||||
|
||||
for err != nil {
|
||||
//nolint:errorlint // We actually do want to check the outermost error.
|
||||
w, ok := err.(wrapped)
|
||||
if !ok {
|
||||
return err
|
||||
|
@ -156,7 +157,6 @@ type multiError struct {
|
|||
func (m multiError) Error() string {
|
||||
return m.aggregate.Error()
|
||||
}
|
||||
|
||||
func (m multiError) Unwrap() []error {
|
||||
return m.aggregate.Errors()
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ type Type string
|
|||
|
||||
// Event types. See below for valid types.
|
||||
// https://godoc.org/k8s.io/client-go/tools/record#EventRecorder
|
||||
const (
|
||||
var (
|
||||
TypeNormal Type = "Normal"
|
||||
TypeWarning Type = "Warning"
|
||||
)
|
||||
|
@ -87,7 +87,7 @@ func NewAPIRecorder(r record.EventRecorder) *APIRecorder {
|
|||
|
||||
// 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), "%s", e.Message)
|
||||
r.kube.AnnotatedEventf(obj, r.annotations, string(e.Type), string(e.Reason), e.Message)
|
||||
}
|
||||
|
||||
// WithAnnotations returns a new *APIRecorder that includes the supplied
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSliceMap(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
from []string
|
||||
to map[string]string
|
||||
|
@ -85,4 +86,5 @@ func TestSliceMap(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,8 +20,3 @@ package feature
|
|||
// 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"
|
||||
|
|
|
@ -72,6 +72,7 @@ func TestSegments(t *testing.T) {
|
|||
if diff := cmp.Diff(tc.want, tc.s.String()); diff != "" {
|
||||
t.Errorf("s.String(): -want, +got:\n %s", diff)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ const (
|
|||
)
|
||||
|
||||
// MergeValue of the receiver p at the specified field path with the supplied
|
||||
// value according to supplied merge options.
|
||||
// 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 {
|
||||
|
@ -93,7 +93,7 @@ func removeSourceDuplicates(dst, src any) any {
|
|||
}
|
||||
|
||||
result := reflect.New(sliceSrc.Type()).Elem() // we will not modify src
|
||||
for i := range sliceSrc.Len() {
|
||||
for i := 0; i < sliceSrc.Len(); i++ {
|
||||
itemSrc := sliceSrc.Index(i)
|
||||
found := false
|
||||
for j := 0; j < sliceDst.Len() && !found; j++ {
|
||||
|
|
|
@ -28,11 +28,11 @@ import (
|
|||
// DefaultMaxFieldPathIndex is the max allowed index in a field path.
|
||||
const DefaultMaxFieldPathIndex = 1024
|
||||
|
||||
type notFoundError struct {
|
||||
type errNotFound struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (e notFoundError) IsNotFound() bool {
|
||||
func (e errNotFound) IsNotFound() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func (e notFoundError) IsNotFound() bool {
|
|||
// index was out of bounds in an array.
|
||||
func IsNotFound(err error) bool {
|
||||
cause := errors.Cause(err)
|
||||
_, ok := cause.(interface {
|
||||
_, ok := cause.(interface { //nolint: errorlint // Skip errorlint for interface type
|
||||
IsNotFound() bool
|
||||
})
|
||||
return ok
|
||||
|
@ -75,9 +75,9 @@ func Pave(object map[string]any, opts ...PavedOption) *Paved {
|
|||
}
|
||||
|
||||
// WithMaxFieldPathIndex returns a PavedOption that sets the max allowed index for field paths, 0 means no limit.
|
||||
func WithMaxFieldPathIndex(maxIndex uint) PavedOption {
|
||||
func WithMaxFieldPathIndex(max uint) PavedOption {
|
||||
return func(paved *Paved) {
|
||||
paved.maxFieldPathIndex = maxIndex
|
||||
paved.maxFieldPathIndex = max
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,29 +121,26 @@ func getValueFromInterface(it any, s Segments) (any, error) {
|
|||
if !ok {
|
||||
return nil, errors.Errorf("%s: not an array", s[:i])
|
||||
}
|
||||
if current.Index >= uint(len(array)) {
|
||||
return nil, notFoundError{errors.Errorf("%s: no such element", s[:i+1])}
|
||||
if int(current.Index) >= len(array) {
|
||||
return nil, errNotFound{errors.Errorf("%s: no such element", s[:i+1])}
|
||||
}
|
||||
if final {
|
||||
return array[current.Index], nil
|
||||
}
|
||||
it = array[current.Index]
|
||||
case SegmentField:
|
||||
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:
|
||||
object, ok := it.(map[string]any)
|
||||
if !ok {
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,7 +156,7 @@ func getValueFromInterface(it any, s Segments) (any, error) {
|
|||
//
|
||||
// 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]"},.
|
||||
// []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 {
|
||||
|
@ -176,7 +173,7 @@ func (p *Paved) ExpandWildcards(path string) ([]string, error) {
|
|||
return paths, nil
|
||||
}
|
||||
|
||||
func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint:gocognit // See note below.
|
||||
func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint:gocyclo // 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
|
||||
|
@ -207,8 +204,6 @@ func expandWildcards(data any, segments Segments) ([]Segments, error) { //nolint
|
|||
}
|
||||
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])
|
||||
}
|
||||
|
@ -306,6 +301,7 @@ func (p *Paved) GetStringObject(path string) (map[string]string, error) {
|
|||
return nil, errors.Errorf("%s: not an object with string field values", path)
|
||||
}
|
||||
so[k] = s
|
||||
|
||||
}
|
||||
|
||||
return so, nil
|
||||
|
@ -427,11 +423,11 @@ func prepareElement(array []any, current, next Segment) {
|
|||
return
|
||||
}
|
||||
|
||||
if next.Index < uint(len(na)) {
|
||||
if int(next.Index) < len(na) {
|
||||
return
|
||||
}
|
||||
|
||||
array[current.Index] = append(na, make([]any, next.Index-uint(len(na))+1)...)
|
||||
array[current.Index] = append(na, make([]any, int(next.Index)-len(na)+1)...)
|
||||
}
|
||||
|
||||
func prepareField(object map[string]any, current, next Segment) {
|
||||
|
@ -458,11 +454,11 @@ func prepareField(object map[string]any, current, next Segment) {
|
|||
return
|
||||
}
|
||||
|
||||
if next.Index < uint(len(na)) {
|
||||
if int(next.Index) < len(na) {
|
||||
return
|
||||
}
|
||||
|
||||
object[current.Field] = append(na, make([]any, next.Index-uint(len(na))+1)...)
|
||||
object[current.Field] = append(na, make([]any, int(next.Index)-len(na)+1)...)
|
||||
}
|
||||
|
||||
// SetValue at the supplied field path.
|
||||
|
@ -514,7 +510,7 @@ func (p *Paved) DeleteField(path string) error {
|
|||
return p.delete(segments)
|
||||
}
|
||||
|
||||
func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note below.
|
||||
func (p *Paved) delete(segments Segments) error { //nolint:gocyclo // See note below.
|
||||
// NOTE(muvaf): I could not reduce the cyclomatic complexity
|
||||
// more than that without disturbing the reading flow.
|
||||
if len(segments) == 1 {
|
||||
|
@ -522,7 +518,7 @@ func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note
|
|||
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.
|
||||
p.object = o.(map[string]any)
|
||||
return nil
|
||||
}
|
||||
var in any = p.object
|
||||
|
@ -543,7 +539,7 @@ func (p *Paved) delete(segments Segments) error { //nolint:gocognit // See note
|
|||
}
|
||||
|
||||
// It doesn't exist anyway.
|
||||
if uint(len(array)) <= current.Index {
|
||||
if len(array) <= int(current.Index) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -593,10 +589,10 @@ func deleteField(obj any, s Segment) (any, error) {
|
|||
if !ok {
|
||||
return nil, errors.New("not an array")
|
||||
}
|
||||
if len(array) == 0 || uint(len(array)) <= s.Index {
|
||||
if len(array) == 0 || len(array) <= int(s.Index) {
|
||||
return array, nil
|
||||
}
|
||||
for i := s.Index; i < uint(len(array))-1; i++ {
|
||||
for i := int(s.Index); i < len(array)-1; i++ {
|
||||
array[i] = array[i+1]
|
||||
}
|
||||
return array[:len(array)-1], nil
|
||||
|
|
|
@ -38,12 +38,12 @@ func TestIsNotFound(t *testing.T) {
|
|||
}{
|
||||
"NotFound": {
|
||||
reason: "An error with method `IsNotFound() bool` should be considered a not found error.",
|
||||
err: notFoundError{errors.New("boom")},
|
||||
err: errNotFound{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(notFoundError{errors.New("boom")}, "because reasons"),
|
||||
err: errors.Wrap(errNotFound{errors.New("boom")}, "because reasons"),
|
||||
want: true,
|
||||
},
|
||||
"SomethingElse": {
|
||||
|
@ -127,7 +127,7 @@ func TestGetValue(t *testing.T) {
|
|||
path: "metadata.name",
|
||||
data: []byte(`{"metadata":{"nope":"cool"}}`),
|
||||
want: want{
|
||||
err: notFoundError{errors.New("metadata.name: no such field")},
|
||||
err: errNotFound{errors.New("metadata.name: no such field")},
|
||||
},
|
||||
},
|
||||
"InsufficientContainers": {
|
||||
|
@ -135,7 +135,7 @@ func TestGetValue(t *testing.T) {
|
|||
path: "spec.containers[1].name",
|
||||
data: []byte(`{"spec":{"containers":[{"name":"cool"}]}}`),
|
||||
want: want{
|
||||
err: notFoundError{errors.New("spec.containers[1]: no such element")},
|
||||
err: errNotFound{errors.New("spec.containers[1]: no such element")},
|
||||
},
|
||||
},
|
||||
"NotAnArray": {
|
||||
|
@ -161,14 +161,6 @@ 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 {
|
||||
|
@ -242,7 +234,7 @@ func TestGetValueInto(t *testing.T) {
|
|||
},
|
||||
want: want{
|
||||
out: &Struct{},
|
||||
err: notFoundError{errors.New("s: no such field")},
|
||||
err: errNotFound{errors.New("s: no such field")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -703,8 +695,7 @@ func TestSetValue(t *testing.T) {
|
|||
},
|
||||
want: want{
|
||||
object: map[string]any{
|
||||
"data": []any{"a"},
|
||||
},
|
||||
"data": []any{"a"}},
|
||||
err: errors.Errorf("index %v is greater than max allowed index %v",
|
||||
DefaultMaxFieldPathIndex+1, DefaultMaxFieldPathIndex),
|
||||
},
|
||||
|
@ -724,8 +715,7 @@ func TestSetValue(t *testing.T) {
|
|||
res[0] = "a"
|
||||
res[DefaultMaxFieldPathIndex+1] = "c"
|
||||
return res
|
||||
}(),
|
||||
},
|
||||
}()},
|
||||
},
|
||||
},
|
||||
"MapStringString": {
|
||||
|
@ -959,14 +949,6 @@ func TestExpandWildcards(t *testing.T) {
|
|||
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 {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
// 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
|
||||
}
|
|
@ -825,7 +825,6 @@ func TestWasDeleted(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWasCreated(t *testing.T) {
|
||||
now := metav1.Now()
|
||||
zero := metav1.Time{}
|
||||
|
@ -1112,6 +1111,7 @@ func TestExternalCreateSucceededDuring(t *testing.T) {
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -51,14 +51,14 @@ 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, _ os.FileInfo) (bool, error) {
|
||||
return func(path string, info os.FileInfo) (bool, error) {
|
||||
return filepath.Match(pattern, path)
|
||||
}
|
||||
}
|
||||
|
||||
// SkipDirs skips directories.
|
||||
func SkipDirs() FilterFn {
|
||||
return func(_ string, info os.FileInfo) (bool, error) {
|
||||
return func(path string, info os.FileInfo) (bool, error) {
|
||||
if info.IsDir() {
|
||||
return true, nil
|
||||
}
|
||||
|
@ -68,14 +68,14 @@ func SkipDirs() FilterFn {
|
|||
|
||||
// SkipEmpty skips empty files.
|
||||
func SkipEmpty() FilterFn {
|
||||
return func(_ string, info os.FileInfo) (bool, error) {
|
||||
return func(path 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, _ os.FileInfo) (bool, error) {
|
||||
return func(path string, info os.FileInfo) (bool, error) {
|
||||
if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func FuzzParse(f *testing.F) {
|
||||
f.Fuzz(func(_ *testing.T, data []byte) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
objScheme := runtime.NewScheme()
|
||||
metaScheme := runtime.NewScheme()
|
||||
p := New(metaScheme, objScheme)
|
||||
|
|
|
@ -32,7 +32,7 @@ const (
|
|||
|
||||
// A Linter lints packages.
|
||||
type Linter interface {
|
||||
Lint(l Lintable) error
|
||||
Lint(Lintable) error
|
||||
}
|
||||
|
||||
// PackageLinterFn lints an entire package. If function applies a check for
|
||||
|
|
|
@ -31,16 +31,16 @@ var _ Linter = &PackageLinter{}
|
|||
var (
|
||||
errBoom = errors.New("boom")
|
||||
|
||||
pkgPass = func(_ Lintable) error {
|
||||
pkgPass = func(lin Lintable) error {
|
||||
return nil
|
||||
}
|
||||
pkgFail = func(_ Lintable) error {
|
||||
pkgFail = func(lin Lintable) error {
|
||||
return errBoom
|
||||
}
|
||||
objPass = func(_ runtime.Object) error {
|
||||
objPass = func(o runtime.Object) error {
|
||||
return nil
|
||||
}
|
||||
objFail = func(_ runtime.Object) error {
|
||||
objFail = func(o runtime.Object) error {
|
||||
return errBoom
|
||||
}
|
||||
)
|
||||
|
|
|
@ -79,7 +79,7 @@ func (p *Package) GetObjects() []runtime.Object {
|
|||
|
||||
// Parser is a package parser.
|
||||
type Parser interface {
|
||||
Parse(ctx context.Context, rc io.ReadCloser) (*Package, error)
|
||||
Parse(context.Context, io.ReadCloser) (*Package, error)
|
||||
}
|
||||
|
||||
// PackageParser is a Parser implementation for parsing packages.
|
||||
|
@ -168,7 +168,7 @@ type BackendOption func(Backend)
|
|||
|
||||
// Backend provides a source for a parser.
|
||||
type Backend interface {
|
||||
Init(ctx context.Context, o ...BackendOption) (io.ReadCloser, error)
|
||||
Init(context.Context, ...BackendOption) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
// PodLogBackend is a parser backend that uses Kubernetes pod logs as source.
|
||||
|
|
|
@ -32,8 +32,6 @@ type Settings struct {
|
|||
}
|
||||
|
||||
// Default password generation settings.
|
||||
//
|
||||
//nolint:gochecknoglobals // We treat this as a constant.
|
||||
var Default = Settings{
|
||||
CharacterSet: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
|
||||
Length: 27,
|
||||
|
@ -48,7 +46,7 @@ func Generate() (string, error) {
|
|||
// Generate a password.
|
||||
func (s Settings) Generate() (string, error) {
|
||||
pw := make([]byte, s.Length)
|
||||
for i := range s.Length {
|
||||
for i := 0; i < s.Length; i++ {
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(s.CharacterSet))))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -23,24 +23,21 @@ import (
|
|||
"golang.org/x/time/rate"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
)
|
||||
|
||||
// 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)}
|
||||
func NewGlobal(rps int) *workqueue.BucketRateLimiter {
|
||||
return &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(rps), rps*10)}
|
||||
}
|
||||
|
||||
// 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)
|
||||
func NewController() ratelimiter.RateLimiter {
|
||||
return workqueue.NewItemExponentialFailureRateLimiter(1*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
// LimitRESTConfig returns a copy of the supplied REST config with rate limits
|
||||
|
|
|
@ -21,23 +21,17 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
"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
|
||||
limit ratelimiter.RateLimiter
|
||||
|
||||
limited map[string]struct{}
|
||||
limitedL sync.RWMutex
|
||||
|
@ -46,7 +40,7 @@ type Reconciler struct {
|
|||
// 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 {
|
||||
func NewReconciler(name string, r reconcile.Reconciler, l ratelimiter.RateLimiter) *Reconciler {
|
||||
return &Reconciler{name: name, inner: r, limit: l, limited: make(map[string]struct{})}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,18 +23,19 @@ import (
|
|||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
)
|
||||
|
||||
var _ RateLimiter = &predictableRateLimiter{}
|
||||
var _ ratelimiter.RateLimiter = &predictableRateLimiter{}
|
||||
|
||||
type predictableRateLimiter struct{ d time.Duration }
|
||||
|
||||
func (r *predictableRateLimiter) When(_ string) time.Duration { return r.d }
|
||||
func (r *predictableRateLimiter) Forget(_ string) {}
|
||||
func (r *predictableRateLimiter) NumRequeues(_ string) int { return 0 }
|
||||
func (r *predictableRateLimiter) When(_ any) time.Duration { return r.d }
|
||||
func (r *predictableRateLimiter) Forget(_ any) {}
|
||||
func (r *predictableRateLimiter) NumRequeues(_ any) int { return 0 }
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
type args struct {
|
||||
|
@ -55,7 +56,7 @@ func TestReconcile(t *testing.T) {
|
|||
"NotRateLimited": {
|
||||
reason: "Requests that are not rate limited should be passed to the inner Reconciler.",
|
||||
r: NewReconciler("test",
|
||||
reconcile.Func(func(_ context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}),
|
||||
&predictableRateLimiter{}),
|
||||
|
@ -75,7 +76,7 @@ func TestReconcile(t *testing.T) {
|
|||
"Returning": {
|
||||
reason: "Returning requests that were previously rate limited should be allowed through without further rate limiting.",
|
||||
r: func() reconcile.Reconciler {
|
||||
inner := reconcile.Func(func(_ context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
inner := reconcile.Func(func(c context.Context, r reconcile.Request) (reconcile.Result, error) {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
})
|
||||
|
||||
|
@ -83,6 +84,7 @@ func TestReconcile(t *testing.T) {
|
|||
r := NewReconciler("test", inner, &predictableRateLimiter{d: 8 * time.Second})
|
||||
r.Reconcile(context.Background(), reconcile.Request{NamespacedName: types.NamespacedName{Name: "limited"}})
|
||||
return r
|
||||
|
||||
}(),
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
|
|
|
@ -18,15 +18,12 @@ package managed
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
@ -36,20 +33,10 @@ import (
|
|||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
)
|
||||
|
||||
const (
|
||||
// fieldOwnerAPISimpleRefResolver owns the reference fields
|
||||
// the managed reconciler resolves.
|
||||
fieldOwnerAPISimpleRefResolver = "managed.crossplane.io/api-simple-reference-resolver"
|
||||
)
|
||||
|
||||
// Error strings.
|
||||
const (
|
||||
errCreateOrUpdateSecret = "cannot create or update connection secret"
|
||||
errUpdateManaged = "cannot update managed resource"
|
||||
errPatchManaged = "cannot patch the managed resource via server-side apply"
|
||||
errMarshalExisting = "cannot marshal the existing object into JSON"
|
||||
errMarshalResolved = "cannot marshal the object with the resolved references into JSON"
|
||||
errPreparePatch = "cannot prepare the JSON merge patch for the resolved object"
|
||||
errUpdateManagedStatus = "cannot update managed resource status"
|
||||
errResolveReferences = "cannot resolve references"
|
||||
errUpdateCriticalAnnotations = "cannot update critical annotations"
|
||||
|
@ -108,7 +95,6 @@ func (a *APISecretPublisher) PublishConnection(ctx context.Context, o resource.C
|
|||
resource.AllowUpdateIf(func(current, desired runtime.Object) bool {
|
||||
// We consider the update to be a no-op and don't allow it if the
|
||||
// current and existing secret data are identical.
|
||||
//nolint:forcetypeassert // Will always be a secret.
|
||||
return !cmp.Equal(current.(*corev1.Secret).Data, desired.(*corev1.Secret).Data, cmpopts.EquateEmpty())
|
||||
}),
|
||||
)
|
||||
|
@ -144,32 +130,11 @@ func NewAPISimpleReferenceResolver(c client.Client) *APISimpleReferenceResolver
|
|||
return &APISimpleReferenceResolver{client: c}
|
||||
}
|
||||
|
||||
func prepareJSONMerge(existing, resolved runtime.Object) ([]byte, error) {
|
||||
// restore the to be replaced GVK so that the existing object is
|
||||
// not modified by this function.
|
||||
defer existing.GetObjectKind().SetGroupVersionKind(existing.GetObjectKind().GroupVersionKind())
|
||||
// we need the apiVersion and kind in the patch document so we set them
|
||||
// to their zero values and make them available in the calculated patch
|
||||
// in the first place, instead of an unmarshal/marshal from the prepared
|
||||
// patch []byte later.
|
||||
existing.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
|
||||
eBuff, err := json.Marshal(existing)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMarshalExisting)
|
||||
}
|
||||
rBuff, err := json.Marshal(resolved)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMarshalResolved)
|
||||
}
|
||||
patch, err := jsonpatch.CreateMergePatch(eBuff, rBuff)
|
||||
return patch, errors.Wrap(err, errPreparePatch)
|
||||
}
|
||||
|
||||
// ResolveReferences of the supplied managed resource by calling its
|
||||
// ResolveReferences method, if any.
|
||||
func (a *APISimpleReferenceResolver) ResolveReferences(ctx context.Context, mg resource.Managed) error {
|
||||
rr, ok := mg.(interface {
|
||||
ResolveReferences(ctx context.Context, r client.Reader) error
|
||||
ResolveReferences(context.Context, client.Reader) error
|
||||
})
|
||||
if !ok {
|
||||
// This managed resource doesn't have any references to resolve.
|
||||
|
@ -181,16 +146,12 @@ func (a *APISimpleReferenceResolver) ResolveReferences(ctx context.Context, mg r
|
|||
return errors.Wrap(err, errResolveReferences)
|
||||
}
|
||||
|
||||
if cmp.Equal(existing, mg, cmpopts.EquateEmpty()) {
|
||||
if cmp.Equal(existing, mg) {
|
||||
// The resource didn't change during reference resolution.
|
||||
return nil
|
||||
}
|
||||
|
||||
patch, err := prepareJSONMerge(existing, mg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.Wrap(a.client.Patch(ctx, mg, client.RawPatch(types.ApplyPatchType, patch), client.FieldOwner(fieldOwnerAPISimpleRefResolver), client.ForceOwnership), errPatchManaged)
|
||||
return errors.Wrap(a.client.Update(ctx, mg), errUpdateManaged)
|
||||
}
|
||||
|
||||
// A RetryingCriticalAnnotationUpdater is a CriticalAnnotationUpdater that
|
||||
|
@ -213,14 +174,10 @@ func NewRetryingCriticalAnnotationUpdater(c client.Client) *RetryingCriticalAnno
|
|||
// case of a conflict error.
|
||||
func (u *RetryingCriticalAnnotationUpdater) UpdateCriticalAnnotations(ctx context.Context, o client.Object) error {
|
||||
a := o.GetAnnotations()
|
||||
err := retry.OnError(retry.DefaultRetry, func(err error) bool {
|
||||
return !errors.Is(err, context.Canceled)
|
||||
}, func() error {
|
||||
err := retry.OnError(retry.DefaultRetry, resource.IsAPIError, func() error {
|
||||
err := u.client.Update(ctx, o)
|
||||
if kerrors.IsConflict(err) {
|
||||
if getErr := u.client.Get(ctx, client.ObjectKeyFromObject(o), o); getErr != nil {
|
||||
return getErr
|
||||
}
|
||||
err = u.client.Get(ctx, types.NamespacedName{Name: o.GetName()}, o)
|
||||
meta.AddAnnotations(o, a)
|
||||
}
|
||||
return err
|
||||
|
|
|
@ -35,7 +35,9 @@ import (
|
|||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
)
|
||||
|
||||
var _ Initializer = &NameAsExternalName{}
|
||||
var (
|
||||
_ Initializer = &NameAsExternalName{}
|
||||
)
|
||||
|
||||
func TestNameAsExternalName(t *testing.T) {
|
||||
type args struct {
|
||||
|
@ -174,11 +176,11 @@ func TestAPISecretPublisher(t *testing.T) {
|
|||
"AlreadyPublished": {
|
||||
reason: "An up to date connection secret should result in no error and not being published",
|
||||
fields: fields{
|
||||
secret: resource.ApplyFn(func(ctx context.Context, o client.Object, ao ...resource.ApplyOption) error {
|
||||
secret: resource.ApplyFn(func(_ context.Context, o client.Object, ao ...resource.ApplyOption) error {
|
||||
want := resource.ConnectionSecretFor(mg, fake.GVK(mg))
|
||||
want.Data = cd
|
||||
for _, fn := range ao {
|
||||
if err := fn(ctx, o, want); err != nil {
|
||||
if err := fn(context.Background(), o, want); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +239,7 @@ func TestAPISecretPublisher(t *testing.T) {
|
|||
type mockSimpleReferencer struct {
|
||||
resource.Managed
|
||||
|
||||
MockResolveReferences func(context.Context, client.Reader) error `json:"-"`
|
||||
MockResolveReferences func(context.Context, client.Reader) error
|
||||
}
|
||||
|
||||
func (r *mockSimpleReferencer) ResolveReferences(ctx context.Context, c client.Reader) error {
|
||||
|
@ -311,7 +313,7 @@ func TestResolveReferences(t *testing.T) {
|
|||
"SuccessfulUpdate": {
|
||||
reason: "Should return without error when a value is successfully resolved.",
|
||||
c: &test.MockClient{
|
||||
MockPatch: test.NewMockPatchFn(nil),
|
||||
MockUpdate: test.NewMockUpdateFn(nil),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
|
@ -325,10 +327,10 @@ func TestResolveReferences(t *testing.T) {
|
|||
},
|
||||
want: nil,
|
||||
},
|
||||
"PatchError": {
|
||||
"UpdateError": {
|
||||
reason: "Should return an error when the managed resource cannot be updated.",
|
||||
c: &test.MockClient{
|
||||
MockPatch: test.NewMockPatchFn(errBoom),
|
||||
MockUpdate: test.NewMockUpdateFn(errBoom),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
|
@ -340,7 +342,7 @@ func TestResolveReferences(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
want: errors.Wrap(errBoom, errPatchManaged),
|
||||
want: errors.Wrap(errBoom, errUpdateManaged),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -355,50 +357,6 @@ func TestResolveReferences(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPrepareJSONMerge(t *testing.T) {
|
||||
type args struct {
|
||||
existing runtime.Object
|
||||
resolved runtime.Object
|
||||
}
|
||||
type want struct {
|
||||
patch string
|
||||
err error
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
"SuccessfulPatch": {
|
||||
reason: "Should successfully compute the JSON merge patch document.",
|
||||
args: args{
|
||||
existing: &fake.Managed{},
|
||||
resolved: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "resolved",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
patch: `{"name":"resolved"}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
patch, err := prepareJSONMerge(tc.args.existing, tc.args.resolved)
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\n%s\nprepareJSONMerge(...): -wantErr, +gotErr:\n%s", tc.reason, diff)
|
||||
}
|
||||
if diff := cmp.Diff(tc.want.patch, string(patch)); diff != "" {
|
||||
t.Errorf("\n%s\nprepareJSONMerge(...): -want, +got:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryingCriticalAnnotationUpdater(t *testing.T) {
|
||||
errBoom := errors.New("boom")
|
||||
|
||||
|
@ -455,26 +413,6 @@ func TestRetryingCriticalAnnotationUpdater(t *testing.T) {
|
|||
o: &fake.Managed{},
|
||||
},
|
||||
},
|
||||
"SuccessfulGetAfterAConflict": {
|
||||
reason: "A successful get after a conflict should not hide the conflict error and prevent retries",
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, setLabels),
|
||||
MockUpdate: test.NewMockUpdateFn(kerrors.NewConflict(schema.GroupResource{
|
||||
Group: "foo.com",
|
||||
Resource: "bars",
|
||||
}, "abc", errBoom)),
|
||||
},
|
||||
args: args{
|
||||
o: &fake.Managed{},
|
||||
},
|
||||
want: want{
|
||||
err: errors.Wrap(kerrors.NewConflict(schema.GroupResource{
|
||||
Group: "foo.com",
|
||||
Resource: "bars",
|
||||
}, "abc", errBoom), errUpdateCriticalAnnotations),
|
||||
o: objectReturnedByGet,
|
||||
},
|
||||
},
|
||||
"Success": {
|
||||
reason: "We should return without error if we successfully update our annotations",
|
||||
c: &test.MockClient{
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
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 managed
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/apis/changelogs/proto/v1alpha1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultSendTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
// ChangeLogger is an interface for recording changes made to resources to the
|
||||
// change logs.
|
||||
type ChangeLogger interface {
|
||||
Log(ctx context.Context, managed resource.Managed, opType v1alpha1.OperationType, changeErr error, ad AdditionalDetails) error
|
||||
}
|
||||
|
||||
// GRPCChangeLogger processes changes to resources and helps to send them to the
|
||||
// change log gRPC service.
|
||||
type GRPCChangeLogger struct {
|
||||
client v1alpha1.ChangeLogServiceClient
|
||||
providerVersion string
|
||||
sendTimeout time.Duration
|
||||
}
|
||||
|
||||
// NewGRPCChangeLogger creates a new gRPC based ChangeLogger initialized with
|
||||
// the given client.
|
||||
func NewGRPCChangeLogger(client v1alpha1.ChangeLogServiceClient, o ...GRPCChangeLoggerOption) *GRPCChangeLogger {
|
||||
g := &GRPCChangeLogger{
|
||||
client: client,
|
||||
sendTimeout: defaultSendTimeout,
|
||||
}
|
||||
|
||||
for _, clo := range o {
|
||||
clo(g)
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// A GRPCChangeLoggerOption configures a GRPCChangeLoggerOption.
|
||||
type GRPCChangeLoggerOption func(*GRPCChangeLogger)
|
||||
|
||||
// WithProviderVersion sets the provider version to be included in the change
|
||||
// log entry.
|
||||
func WithProviderVersion(version string) GRPCChangeLoggerOption {
|
||||
return func(g *GRPCChangeLogger) {
|
||||
g.providerVersion = version
|
||||
}
|
||||
}
|
||||
|
||||
// WithSendTimeout sets the timeout for sending and/or waiting for change log
|
||||
// entries to the change log service.
|
||||
func WithSendTimeout(timeout time.Duration) GRPCChangeLoggerOption {
|
||||
return func(g *GRPCChangeLogger) {
|
||||
g.sendTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// Log sends the given change log entry to the change log service.
|
||||
func (g *GRPCChangeLogger) Log(ctx context.Context, managed resource.Managed, opType v1alpha1.OperationType, changeErr error, ad AdditionalDetails) error {
|
||||
// get an error message from the error if it exists
|
||||
var changeErrMessage *string
|
||||
if changeErr != nil {
|
||||
changeErrMessage = ptr.To(changeErr.Error())
|
||||
}
|
||||
|
||||
// capture the full state of the managed resource from before we performed the change
|
||||
snapshot, err := resource.AsProtobufStruct(managed)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot snapshot managed resource")
|
||||
}
|
||||
|
||||
gvk := managed.GetObjectKind().GroupVersionKind()
|
||||
|
||||
entry := &v1alpha1.ChangeLogEntry{
|
||||
Timestamp: timestamppb.Now(),
|
||||
Provider: g.providerVersion,
|
||||
ApiVersion: gvk.GroupVersion().String(),
|
||||
Kind: gvk.Kind,
|
||||
Name: managed.GetName(),
|
||||
ExternalName: meta.GetExternalName(managed),
|
||||
Operation: opType,
|
||||
Snapshot: snapshot,
|
||||
ErrorMessage: changeErrMessage,
|
||||
AdditionalDetails: ad,
|
||||
}
|
||||
|
||||
// create a specific context and timeout for sending the change log entry
|
||||
// that is different than the parent context that is for the entire
|
||||
// reconciliation
|
||||
sendCtx, sendCancel := context.WithTimeout(ctx, g.sendTimeout)
|
||||
defer sendCancel()
|
||||
|
||||
// send everything we've got to the change log service
|
||||
_, err = g.client.SendChangeLog(sendCtx, &v1alpha1.SendChangeLogRequest{Entry: entry}, grpc.WaitForReady(true))
|
||||
return errors.Wrap(err, "cannot send change log entry")
|
||||
}
|
||||
|
||||
// nopChangeLogger does nothing for recording change logs, this is the default
|
||||
// implementation if a provider has not enabled the change logs feature.
|
||||
type nopChangeLogger struct{}
|
||||
|
||||
func newNopChangeLogger() *nopChangeLogger {
|
||||
return &nopChangeLogger{}
|
||||
}
|
||||
|
||||
func (n *nopChangeLogger) Log(_ context.Context, _ resource.Managed, _ v1alpha1.OperationType, _ error, _ AdditionalDetails) error {
|
||||
return nil
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
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 managed
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/apis/changelogs/proto/v1alpha1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
)
|
||||
|
||||
// A mock implementation of the ChangeLogServiceClient interface to help with
|
||||
// testing and verifying change log entries.
|
||||
type changeLogServiceClient struct {
|
||||
requests []*v1alpha1.SendChangeLogRequest
|
||||
sendFn func(ctx context.Context, in *v1alpha1.SendChangeLogRequest, opts ...grpc.CallOption) (*v1alpha1.SendChangeLogResponse, error)
|
||||
}
|
||||
|
||||
func (c *changeLogServiceClient) SendChangeLog(ctx context.Context, in *v1alpha1.SendChangeLogRequest, opts ...grpc.CallOption) (*v1alpha1.SendChangeLogResponse, error) {
|
||||
c.requests = append(c.requests, in)
|
||||
if c.sendFn != nil {
|
||||
return c.sendFn(ctx, in, opts...)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestChangeLogger(t *testing.T) {
|
||||
type args struct {
|
||||
mr resource.Managed
|
||||
ad AdditionalDetails
|
||||
err error
|
||||
c *changeLogServiceClient
|
||||
}
|
||||
|
||||
type want struct {
|
||||
requests []*v1alpha1.SendChangeLogRequest
|
||||
err error
|
||||
}
|
||||
|
||||
errBoom := errors.New("boom")
|
||||
|
||||
cases := map[string]struct {
|
||||
reason string
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
"ChangeLogsSuccess": {
|
||||
reason: "Change log entry should be recorded successfully.",
|
||||
args: args{
|
||||
mr: &fake.Managed{ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cool-managed",
|
||||
Annotations: map[string]string{meta.AnnotationKeyExternalName: "cool-managed"},
|
||||
}},
|
||||
err: errBoom,
|
||||
ad: AdditionalDetails{"key": "value", "key2": "value2"},
|
||||
c: &changeLogServiceClient{requests: []*v1alpha1.SendChangeLogRequest{}},
|
||||
},
|
||||
want: want{
|
||||
// a well fleshed out change log entry should be sent
|
||||
requests: []*v1alpha1.SendChangeLogRequest{
|
||||
{
|
||||
Entry: &v1alpha1.ChangeLogEntry{
|
||||
Timestamp: timestamppb.Now(),
|
||||
Provider: "provider-cool:v9.99.999",
|
||||
ApiVersion: (&fake.Managed{}).GetObjectKind().GroupVersionKind().GroupVersion().String(),
|
||||
Kind: (&fake.Managed{}).GetObjectKind().GroupVersionKind().Kind,
|
||||
Name: "cool-managed",
|
||||
ExternalName: "cool-managed",
|
||||
Operation: v1alpha1.OperationType_OPERATION_TYPE_CREATE,
|
||||
Snapshot: mustObjectAsProtobufStruct(&fake.Managed{ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cool-managed",
|
||||
Annotations: map[string]string{meta.AnnotationKeyExternalName: "cool-managed"},
|
||||
}}),
|
||||
ErrorMessage: ptr.To("boom"),
|
||||
AdditionalDetails: AdditionalDetails{"key": "value", "key2": "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"SendChangeLogsFailure": {
|
||||
reason: "Error from sending change log entry should be handled and recorded.",
|
||||
args: args{
|
||||
mr: &fake.Managed{},
|
||||
c: &changeLogServiceClient{
|
||||
requests: []*v1alpha1.SendChangeLogRequest{},
|
||||
// make the send change log function return an error
|
||||
sendFn: func(_ context.Context, _ *v1alpha1.SendChangeLogRequest, _ ...grpc.CallOption) (*v1alpha1.SendChangeLogResponse, error) {
|
||||
return &v1alpha1.SendChangeLogResponse{}, errBoom
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
// we'll still see a change log entry, but it won't make it all
|
||||
// the way to its destination and we should see an event for
|
||||
// that failure
|
||||
requests: []*v1alpha1.SendChangeLogRequest{
|
||||
{
|
||||
Entry: &v1alpha1.ChangeLogEntry{
|
||||
// we expect less fields to be set on the change log
|
||||
// entry because we're not initializing the managed
|
||||
// resource with much data in this simulated failure
|
||||
// test case
|
||||
Timestamp: timestamppb.Now(),
|
||||
Provider: "provider-cool:v9.99.999",
|
||||
ApiVersion: (&fake.Managed{}).GetObjectKind().GroupVersionKind().GroupVersion().String(),
|
||||
Kind: (&fake.Managed{}).GetObjectKind().GroupVersionKind().Kind,
|
||||
Operation: v1alpha1.OperationType_OPERATION_TYPE_CREATE,
|
||||
Snapshot: mustObjectAsProtobufStruct(&fake.Managed{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
err: errors.Wrap(errBoom, "cannot send change log entry"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
change := NewGRPCChangeLogger(tc.args.c, WithProviderVersion("provider-cool:v9.99.999"))
|
||||
err := change.Log(context.Background(), tc.args.mr, v1alpha1.OperationType_OPERATION_TYPE_CREATE, tc.args.err, tc.args.ad)
|
||||
|
||||
if diff := cmp.Diff(tc.want.requests, tc.args.c.requests, equateApproxTimepb(time.Second)...); diff != "" {
|
||||
t.Errorf("\nReason: %s\nr.RecordChangeLog(...): -want requests, +got requests:\n%s", tc.reason, diff)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("\nReason: %s\nr.RecordChangeLog(...): -want error, +got error:\n%s", tc.reason, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mustObjectAsProtobufStruct(o runtime.Object) *structpb.Struct {
|
||||
s, err := resource.AsProtobufStruct(o)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// A set of cmp.Option that enables usage of cmpopts.EquateApproxTime for
|
||||
// timestamppb.Timestamp types.
|
||||
// Source: https://github.com/golang/protobuf/issues/1347
|
||||
func equateApproxTimepb(margin time.Duration) []cmp.Option {
|
||||
return cmp.Options{
|
||||
cmpopts.EquateApproxTime(margin),
|
||||
protocmp.Transform(),
|
||||
cmp.FilterPath(
|
||||
func(p cmp.Path) bool {
|
||||
if p.Last().Type() == reflect.TypeOf(protocmp.Message{}) {
|
||||
a, b := p.Last().Values()
|
||||
return msgIsTimestamp(a) && msgIsTimestamp(b)
|
||||
}
|
||||
return false
|
||||
},
|
||||
cmp.Transformer("timestamppb", func(t protocmp.Message) time.Time {
|
||||
return time.Unix(t["seconds"].(int64), int64(t["nanos"].(int32))).UTC()
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func msgIsTimestamp(x reflect.Value) bool {
|
||||
return x.Interface().(protocmp.Message).Descriptor().FullName() == "google.protobuf.Timestamp"
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
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 managed
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kmetrics "k8s.io/component-base/metrics"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
)
|
||||
|
||||
const subSystem = "crossplane"
|
||||
|
||||
// MetricRecorder records the managed resource metrics.
|
||||
type MetricRecorder interface { //nolint:interfacebloat // The first two methods are coming from Prometheus
|
||||
Describe(ch chan<- *prometheus.Desc)
|
||||
Collect(ch chan<- prometheus.Metric)
|
||||
|
||||
recordUnchanged(name string)
|
||||
recordFirstTimeReconciled(managed resource.Managed)
|
||||
recordFirstTimeReady(managed resource.Managed)
|
||||
recordDrift(managed resource.Managed)
|
||||
recordDeleted(managed resource.Managed)
|
||||
}
|
||||
|
||||
// MRMetricRecorder records the lifecycle metrics of managed resources.
|
||||
type MRMetricRecorder struct {
|
||||
firstObservation sync.Map
|
||||
lastObservation sync.Map
|
||||
|
||||
mrDetected *prometheus.HistogramVec
|
||||
mrFirstTimeReady *prometheus.HistogramVec
|
||||
mrDeletion *prometheus.HistogramVec
|
||||
mrDrift *prometheus.HistogramVec
|
||||
}
|
||||
|
||||
// NewMRMetricRecorder returns a new MRMetricRecorder which records metrics for managed resources.
|
||||
func NewMRMetricRecorder() *MRMetricRecorder {
|
||||
return &MRMetricRecorder{
|
||||
mrDetected: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: subSystem,
|
||||
Name: "managed_resource_first_time_to_reconcile_seconds",
|
||||
Help: "The time it took for a managed resource to be detected by the controller",
|
||||
Buckets: kmetrics.ExponentialBuckets(10e-9, 10, 10),
|
||||
}, []string{"gvk"}),
|
||||
mrFirstTimeReady: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: subSystem,
|
||||
Name: "managed_resource_first_time_to_readiness_seconds",
|
||||
Help: "The time it took for a managed resource to become ready first time after creation",
|
||||
Buckets: []float64{1, 5, 10, 15, 30, 60, 120, 300, 600, 1800, 3600},
|
||||
}, []string{"gvk"}),
|
||||
mrDeletion: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: subSystem,
|
||||
Name: "managed_resource_deletion_seconds",
|
||||
Help: "The time it took for a managed resource to be deleted",
|
||||
Buckets: []float64{1, 5, 10, 15, 30, 60, 120, 300, 600, 1800, 3600},
|
||||
}, []string{"gvk"}),
|
||||
mrDrift: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: subSystem,
|
||||
Name: "managed_resource_drift_seconds",
|
||||
Help: "ALPHA: How long since the previous successful reconcile when a resource was found to be out of sync; excludes restart of the provider",
|
||||
Buckets: kmetrics.ExponentialBuckets(10e-9, 10, 10),
|
||||
}, []string{"gvk"}),
|
||||
}
|
||||
}
|
||||
|
||||
// Describe sends the super-set of all possible descriptors of metrics
|
||||
// collected by this Collector to the provided channel and returns once
|
||||
// the last descriptor has been sent.
|
||||
func (r *MRMetricRecorder) Describe(ch chan<- *prometheus.Desc) {
|
||||
r.mrDetected.Describe(ch)
|
||||
r.mrFirstTimeReady.Describe(ch)
|
||||
r.mrDeletion.Describe(ch)
|
||||
r.mrDrift.Describe(ch)
|
||||
}
|
||||
|
||||
// Collect is called by the Prometheus registry when collecting
|
||||
// metrics. The implementation sends each collected metric via the
|
||||
// provided channel and returns once the last metric has been sent.
|
||||
func (r *MRMetricRecorder) Collect(ch chan<- prometheus.Metric) {
|
||||
r.mrDetected.Collect(ch)
|
||||
r.mrFirstTimeReady.Collect(ch)
|
||||
r.mrDeletion.Collect(ch)
|
||||
r.mrDrift.Collect(ch)
|
||||
}
|
||||
|
||||
func (r *MRMetricRecorder) recordUnchanged(name string) {
|
||||
r.lastObservation.Store(name, time.Now())
|
||||
}
|
||||
|
||||
func (r *MRMetricRecorder) recordFirstTimeReconciled(managed resource.Managed) {
|
||||
if managed.GetCondition(xpv1.TypeSynced).Status == corev1.ConditionUnknown {
|
||||
r.mrDetected.With(getLabels(managed)).Observe(time.Since(managed.GetCreationTimestamp().Time).Seconds())
|
||||
r.firstObservation.Store(managed.GetName(), time.Now()) // this is the first time we reconciled on this resource
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MRMetricRecorder) recordDrift(managed resource.Managed) {
|
||||
name := managed.GetName()
|
||||
last, ok := r.lastObservation.Load(name)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
lt, ok := last.(time.Time)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
r.mrDrift.With(getLabels(managed)).Observe(time.Since(lt).Seconds())
|
||||
|
||||
r.lastObservation.Store(name, time.Now())
|
||||
}
|
||||
|
||||
func (r *MRMetricRecorder) recordDeleted(managed resource.Managed) {
|
||||
r.mrDeletion.With(getLabels(managed)).Observe(time.Since(managed.GetDeletionTimestamp().Time).Seconds())
|
||||
}
|
||||
|
||||
func (r *MRMetricRecorder) recordFirstTimeReady(managed resource.Managed) {
|
||||
// Note that providers may set the ready condition to "True", so we need
|
||||
// to check the value here to send the ready metric
|
||||
if managed.GetCondition(xpv1.TypeReady).Status == corev1.ConditionTrue {
|
||||
_, ok := r.firstObservation.Load(managed.GetName()) // This map is used to identify the first time to readiness
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
r.mrFirstTimeReady.With(getLabels(managed)).Observe(time.Since(managed.GetCreationTimestamp().Time).Seconds())
|
||||
r.firstObservation.Delete(managed.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
// A NopMetricRecorder does nothing.
|
||||
type NopMetricRecorder struct{}
|
||||
|
||||
// NewNopMetricRecorder returns a MRMetricRecorder that does nothing.
|
||||
func NewNopMetricRecorder() *NopMetricRecorder {
|
||||
return &NopMetricRecorder{}
|
||||
}
|
||||
|
||||
// Describe does nothing.
|
||||
func (r *NopMetricRecorder) Describe(_ chan<- *prometheus.Desc) {}
|
||||
|
||||
// Collect does nothing.
|
||||
func (r *NopMetricRecorder) Collect(_ chan<- prometheus.Metric) {}
|
||||
|
||||
func (r *NopMetricRecorder) recordUnchanged(_ string) {}
|
||||
|
||||
func (r *NopMetricRecorder) recordFirstTimeReconciled(_ resource.Managed) {}
|
||||
|
||||
func (r *NopMetricRecorder) recordDrift(_ resource.Managed) {}
|
||||
|
||||
func (r *NopMetricRecorder) recordDeleted(_ resource.Managed) {}
|
||||
|
||||
func (r *NopMetricRecorder) recordFirstTimeReady(_ resource.Managed) {}
|
||||
|
||||
func getLabels(r resource.Managed) prometheus.Labels {
|
||||
return prometheus.Labels{
|
||||
"gvk": r.GetObjectKind().GroupVersionKind().String(),
|
||||
}
|
||||
}
|
|
@ -82,21 +82,6 @@ func defaultSupportedManagementPolicies() []sets.Set[xpv1.ManagementAction] {
|
|||
// is not deleted when the managed resource is deleted and the
|
||||
// spec.forProvider is not late initialized.
|
||||
sets.New[xpv1.ManagementAction](xpv1.ManagementActionObserve, xpv1.ManagementActionCreate),
|
||||
// Like ObserveOnly, but the external resource is deleted when the
|
||||
// managed resource is deleted.
|
||||
sets.New[xpv1.ManagementAction](xpv1.ManagementActionObserve, xpv1.ManagementActionDelete),
|
||||
// No Crate and no Delete. Just update/patch the external resource.
|
||||
// Useful when the same external resource is managed by multiple
|
||||
// managed resources.
|
||||
sets.New[xpv1.ManagementAction](xpv1.ManagementActionObserve, xpv1.ManagementActionUpdate),
|
||||
// Import mode: Allows observation of existing resources and populates spec.forProvider
|
||||
// through late initialization, without making any changes to the external resource.
|
||||
// Useful for safely importing existing resources to discover their current state.
|
||||
sets.New[xpv1.ManagementAction](xpv1.ManagementActionObserve, xpv1.ManagementActionLateInitialize),
|
||||
// No Create, no Delete. Just Observe, Update and LateInitialize.
|
||||
// Useful when external resource lifecycle is managed elsewhere but you want
|
||||
// to allow Crossplane to make updates and discover state changes.
|
||||
sets.New[xpv1.ManagementAction](xpv1.ManagementActionObserve, xpv1.ManagementActionUpdate, xpv1.ManagementActionLateInitialize),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,7 +128,7 @@ func (m *ManagementPoliciesResolver) Validate() error {
|
|||
}
|
||||
|
||||
// IsPaused returns true if the management policy is empty and the
|
||||
// management policies feature is enabled.
|
||||
// management policies feature is enabled
|
||||
func (m *ManagementPoliciesResolver) IsPaused() bool {
|
||||
if !m.enabled {
|
||||
return false
|
||||
|
|
|
@ -57,7 +57,8 @@ func (pc PublisherChain) UnpublishConnection(ctx context.Context, o resource.Con
|
|||
|
||||
// DisabledSecretStoreManager is a connection details manager that returns a proper
|
||||
// error when API used but feature not enabled.
|
||||
type DisabledSecretStoreManager struct{}
|
||||
type DisabledSecretStoreManager struct {
|
||||
}
|
||||
|
||||
// PublishConnection returns a proper error when API used but the feature was
|
||||
// not enabled.
|
||||
|
|
|
@ -64,10 +64,10 @@ func TestPublisherChain(t *testing.T) {
|
|||
"SuccessfulPublisher": {
|
||||
p: PublisherChain{
|
||||
ConnectionPublisherFns{
|
||||
PublishConnectionFn: func(_ context.Context, _ resource.ConnectionSecretOwner, _ ConnectionDetails) (bool, error) {
|
||||
PublishConnectionFn: func(_ context.Context, o resource.ConnectionSecretOwner, c ConnectionDetails) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
UnpublishConnectionFn: func(_ context.Context, _ resource.ConnectionSecretOwner, _ ConnectionDetails) error {
|
||||
UnpublishConnectionFn: func(ctx context.Context, o resource.ConnectionSecretOwner, c ConnectionDetails) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
@ -84,10 +84,10 @@ func TestPublisherChain(t *testing.T) {
|
|||
"PublisherReturnsError": {
|
||||
p: PublisherChain{
|
||||
ConnectionPublisherFns{
|
||||
PublishConnectionFn: func(_ context.Context, _ resource.ConnectionSecretOwner, _ ConnectionDetails) (bool, error) {
|
||||
PublishConnectionFn: func(_ context.Context, o resource.ConnectionSecretOwner, c ConnectionDetails) (bool, error) {
|
||||
return false, errBoom
|
||||
},
|
||||
UnpublishConnectionFn: func(_ context.Context, _ resource.ConnectionSecretOwner, _ ConnectionDetails) error {
|
||||
UnpublishConnectionFn: func(ctx context.Context, o resource.ConnectionSecretOwner, c ConnectionDetails) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
|
|
|
@ -29,9 +29,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/apis/changelogs/proto/v1alpha1"
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/conditions"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/event"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/feature"
|
||||
|
@ -65,7 +63,6 @@ const (
|
|||
errReconcileCreate = "create failed"
|
||||
errReconcileUpdate = "update failed"
|
||||
errReconcileDelete = "delete failed"
|
||||
errRecordChangeLog = "cannot record change log entry"
|
||||
|
||||
errExternalResourceNotExist = "external resource does not exist"
|
||||
)
|
||||
|
@ -102,7 +99,7 @@ func ControllerName(kind string) string {
|
|||
// ManagementPoliciesChecker is used to perform checks on management policies
|
||||
// to determine specific actions are allowed, or if they are the only allowed
|
||||
// action.
|
||||
type ManagementPoliciesChecker interface { //nolint:interfacebloat // This has to be big.
|
||||
type ManagementPoliciesChecker interface {
|
||||
// Validate validates the management policies.
|
||||
Validate() error
|
||||
// IsPaused returns true if the resource is paused based
|
||||
|
@ -141,11 +138,6 @@ func (fn CriticalAnnotationUpdateFn) UpdateCriticalAnnotations(ctx context.Conte
|
|||
// resource, for example usernames, passwords, endpoints, ports, etc.
|
||||
type ConnectionDetails map[string][]byte
|
||||
|
||||
// AdditionalDetails represent any additional details the external client wants
|
||||
// to return about an operation that has been performed. These details will be
|
||||
// included in the change logs.
|
||||
type AdditionalDetails map[string]string
|
||||
|
||||
// A ConnectionPublisher manages the supplied ConnectionDetails for the
|
||||
// supplied Managed resource. ManagedPublishers must handle the case in which
|
||||
// the supplied ConnectionDetails are empty.
|
||||
|
@ -181,7 +173,7 @@ type ConnectionDetailsFetcher interface {
|
|||
FetchConnection(ctx context.Context, so resource.ConnectionSecretOwner) (ConnectionDetails, error)
|
||||
}
|
||||
|
||||
// Initializer establishes ownership of the supplied Managed resource.
|
||||
// A Initializer establishes ownership of the supplied Managed resource.
|
||||
// This typically involves the operations that are run before calling any
|
||||
// ExternalClient methods.
|
||||
type Initializer interface {
|
||||
|
@ -224,81 +216,65 @@ type ReferenceResolver interface {
|
|||
// ReferenceResolver interface.
|
||||
type ReferenceResolverFn func(context.Context, resource.Managed) error
|
||||
|
||||
// ResolveReferences calls ReferenceResolverFn function.
|
||||
// ResolveReferences calls ReferenceResolverFn function
|
||||
func (m ReferenceResolverFn) ResolveReferences(ctx context.Context, mg resource.Managed) error {
|
||||
return m(ctx, mg)
|
||||
}
|
||||
|
||||
// An ExternalConnector produces a new ExternalClient given the supplied
|
||||
// An ExternalConnecter produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type ExternalConnector = TypedExternalConnector[resource.Managed]
|
||||
|
||||
// A TypedExternalConnector produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type TypedExternalConnector[managed resource.Managed] interface {
|
||||
type ExternalConnecter interface {
|
||||
// Connect to the provider specified by the supplied managed resource and
|
||||
// produce an ExternalClient.
|
||||
Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error)
|
||||
Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error)
|
||||
}
|
||||
|
||||
// A NopDisconnector converts an ExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
type NopDisconnector = TypedNopDisconnector[resource.Managed]
|
||||
|
||||
// A TypedNopDisconnector converts an ExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
type TypedNopDisconnector[managed resource.Managed] struct {
|
||||
c TypedExternalConnector[managed]
|
||||
// An ExternalDisconnecter disconnects from a provider.
|
||||
type ExternalDisconnecter interface {
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
Disconnect(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Connect calls the underlying ExternalConnector's Connect method.
|
||||
func (c *TypedNopDisconnector[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
// A NopDisconnecter converts an ExternalConnecter into an
|
||||
// ExternalConnectDisconnecter with a no-op Disconnect method.
|
||||
type NopDisconnecter struct {
|
||||
c ExternalConnecter
|
||||
}
|
||||
|
||||
// Connect calls the underlying ExternalConnecter's Connect method.
|
||||
func (c *NopDisconnecter) Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error) {
|
||||
return c.c.Connect(ctx, mg)
|
||||
}
|
||||
|
||||
// Disconnect does nothing. It never returns an error.
|
||||
func (c *TypedNopDisconnector[managed]) Disconnect(_ context.Context) error {
|
||||
func (c *NopDisconnecter) Disconnect(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewNopDisconnector converts an ExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
func NewNopDisconnector(c ExternalConnector) ExternalConnectDisconnector {
|
||||
return NewTypedNopDisconnector(c)
|
||||
// NewNopDisconnecter converts an ExternalConnecter into an
|
||||
// ExternalConnectDisconnecter with a no-op Disconnect method.
|
||||
func NewNopDisconnecter(c ExternalConnecter) ExternalConnectDisconnecter {
|
||||
return &NopDisconnecter{c}
|
||||
}
|
||||
|
||||
// NewTypedNopDisconnector converts an TypedExternalConnector into an
|
||||
// ExternalConnectDisconnector with a no-op Disconnect method.
|
||||
func NewTypedNopDisconnector[managed resource.Managed](c TypedExternalConnector[managed]) TypedExternalConnectDisconnector[managed] {
|
||||
return &TypedNopDisconnector[managed]{c}
|
||||
}
|
||||
|
||||
// An ExternalConnectDisconnector produces a new ExternalClient given the supplied
|
||||
// An ExternalConnectDisconnecter produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type ExternalConnectDisconnector = TypedExternalConnectDisconnector[resource.Managed]
|
||||
|
||||
// A TypedExternalConnectDisconnector produces a new ExternalClient given the supplied
|
||||
// Managed resource.
|
||||
type TypedExternalConnectDisconnector[managed resource.Managed] interface {
|
||||
TypedExternalConnector[managed]
|
||||
ExternalDisconnector
|
||||
type ExternalConnectDisconnecter interface {
|
||||
ExternalConnecter
|
||||
ExternalDisconnecter
|
||||
}
|
||||
|
||||
// An ExternalConnectorFn is a function that satisfies the ExternalConnector
|
||||
// An ExternalConnectorFn is a function that satisfies the ExternalConnecter
|
||||
// interface.
|
||||
type ExternalConnectorFn = TypedExternalConnectorFn[resource.Managed]
|
||||
|
||||
// An TypedExternalConnectorFn is a function that satisfies the
|
||||
// TypedExternalConnector interface.
|
||||
type TypedExternalConnectorFn[managed resource.Managed] func(ctx context.Context, mg managed) (TypedExternalClient[managed], error)
|
||||
type ExternalConnectorFn func(ctx context.Context, mg resource.Managed) (ExternalClient, error)
|
||||
|
||||
// Connect to the provider specified by the supplied managed resource and
|
||||
// produce an ExternalClient.
|
||||
func (ec TypedExternalConnectorFn[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
func (ec ExternalConnectorFn) Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error) {
|
||||
return ec(ctx, mg)
|
||||
}
|
||||
|
||||
// An ExternalDisconnectorFn is a function that satisfies the ExternalConnector
|
||||
// An ExternalDisconnectorFn is a function that satisfies the ExternalConnecter
|
||||
// interface.
|
||||
type ExternalDisconnectorFn func(ctx context.Context) error
|
||||
|
||||
|
@ -307,25 +283,21 @@ func (ed ExternalDisconnectorFn) Disconnect(ctx context.Context) error {
|
|||
return ed(ctx)
|
||||
}
|
||||
|
||||
// ExternalConnectDisconnectorFns are functions that satisfy the
|
||||
// ExternalConnectDisconnector interface.
|
||||
type ExternalConnectDisconnectorFns = TypedExternalConnectDisconnectorFns[resource.Managed]
|
||||
|
||||
// TypedExternalConnectDisconnectorFns are functions that satisfy the
|
||||
// TypedExternalConnectDisconnector interface.
|
||||
type TypedExternalConnectDisconnectorFns[managed resource.Managed] struct {
|
||||
ConnectFn func(ctx context.Context, mg managed) (TypedExternalClient[managed], error)
|
||||
// ExternalConnectDisconnecterFns are functions that satisfy the
|
||||
// ExternalConnectDisconnecter interface.
|
||||
type ExternalConnectDisconnecterFns struct {
|
||||
ConnectFn func(ctx context.Context, mg resource.Managed) (ExternalClient, error)
|
||||
DisconnectFn func(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Connect to the provider specified by the supplied managed resource and
|
||||
// produce an ExternalClient.
|
||||
func (fns TypedExternalConnectDisconnectorFns[managed]) Connect(ctx context.Context, mg managed) (TypedExternalClient[managed], error) {
|
||||
func (fns ExternalConnectDisconnecterFns) Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error) {
|
||||
return fns.ConnectFn(ctx, mg)
|
||||
}
|
||||
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
func (fns TypedExternalConnectDisconnectorFns[managed]) Disconnect(ctx context.Context) error {
|
||||
func (fns ExternalConnectDisconnecterFns) Disconnect(ctx context.Context) error {
|
||||
return fns.DisconnectFn(ctx)
|
||||
}
|
||||
|
||||
|
@ -334,93 +306,70 @@ func (fns TypedExternalConnectDisconnectorFns[managed]) Disconnect(ctx context.C
|
|||
// idempotent. For example, Create call should not return AlreadyExists error
|
||||
// if it's called again with the same parameters or Delete call should not
|
||||
// return error if there is an ongoing deletion or resource does not exist.
|
||||
type ExternalClient = TypedExternalClient[resource.Managed]
|
||||
|
||||
// A TypedExternalClient manages the lifecycle of an external resource.
|
||||
// None of the calls here should be blocking. All of the calls should be
|
||||
// idempotent. For example, Create call should not return AlreadyExists error
|
||||
// if it's called again with the same parameters or Delete call should not
|
||||
// return error if there is an ongoing deletion or resource does not exist.
|
||||
type TypedExternalClient[managedType resource.Managed] interface {
|
||||
type ExternalClient interface {
|
||||
// Observe the external resource the supplied Managed resource
|
||||
// represents, if any. Observe implementations must not modify the
|
||||
// external resource, but may update the supplied Managed resource to
|
||||
// reflect the state of the external resource. Status modifications are
|
||||
// automatically persisted unless ResourceLateInitialized is true - see
|
||||
// ResourceLateInitialized for more detail.
|
||||
Observe(ctx context.Context, mg managedType) (ExternalObservation, error)
|
||||
Observe(ctx context.Context, mg resource.Managed) (ExternalObservation, error)
|
||||
|
||||
// Create an external resource per the specifications of the supplied
|
||||
// Managed resource. Called when Observe reports that the associated
|
||||
// external resource does not exist. Create implementations may update
|
||||
// managed resource annotations, and those updates will be persisted.
|
||||
// All other updates will be discarded.
|
||||
Create(ctx context.Context, mg managedType) (ExternalCreation, error)
|
||||
Create(ctx context.Context, mg resource.Managed) (ExternalCreation, error)
|
||||
|
||||
// Update the external resource represented by the supplied Managed
|
||||
// resource, if necessary. Called unless Observe reports that the
|
||||
// associated external resource is up to date.
|
||||
Update(ctx context.Context, mg managedType) (ExternalUpdate, error)
|
||||
Update(ctx context.Context, mg resource.Managed) (ExternalUpdate, error)
|
||||
|
||||
// Delete the external resource upon deletion of its associated Managed
|
||||
// resource. Called when the managed resource has been deleted.
|
||||
Delete(ctx context.Context, mg managedType) (ExternalDelete, error)
|
||||
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
// Called at the end of reconcile loop. An ExternalClient not requiring
|
||||
// to explicitly disconnect to cleanup it resources, can provide a no-op
|
||||
// implementation which just return nil.
|
||||
Disconnect(ctx context.Context) error
|
||||
Delete(ctx context.Context, mg resource.Managed) error
|
||||
}
|
||||
|
||||
// ExternalClientFns are a series of functions that satisfy the ExternalClient
|
||||
// interface.
|
||||
type ExternalClientFns = TypedExternalClientFns[resource.Managed]
|
||||
|
||||
// TypedExternalClientFns are a series of functions that satisfy the
|
||||
// ExternalClient interface.
|
||||
type TypedExternalClientFns[managed resource.Managed] struct {
|
||||
ObserveFn func(ctx context.Context, mg managed) (ExternalObservation, error)
|
||||
CreateFn func(ctx context.Context, mg managed) (ExternalCreation, error)
|
||||
UpdateFn func(ctx context.Context, mg managed) (ExternalUpdate, error)
|
||||
DeleteFn func(ctx context.Context, mg managed) (ExternalDelete, error)
|
||||
DisconnectFn func(ctx context.Context) error
|
||||
type ExternalClientFns struct {
|
||||
ObserveFn func(ctx context.Context, mg resource.Managed) (ExternalObservation, error)
|
||||
CreateFn func(ctx context.Context, mg resource.Managed) (ExternalCreation, error)
|
||||
UpdateFn func(ctx context.Context, mg resource.Managed) (ExternalUpdate, error)
|
||||
DeleteFn func(ctx context.Context, mg resource.Managed) error
|
||||
}
|
||||
|
||||
// Observe the external resource the supplied Managed resource represents, if
|
||||
// any.
|
||||
func (e TypedExternalClientFns[managed]) Observe(ctx context.Context, mg managed) (ExternalObservation, error) {
|
||||
func (e ExternalClientFns) Observe(ctx context.Context, mg resource.Managed) (ExternalObservation, error) {
|
||||
return e.ObserveFn(ctx, mg)
|
||||
}
|
||||
|
||||
// Create an external resource per the specifications of the supplied Managed
|
||||
// resource.
|
||||
func (e TypedExternalClientFns[managed]) Create(ctx context.Context, mg managed) (ExternalCreation, error) {
|
||||
func (e ExternalClientFns) Create(ctx context.Context, mg resource.Managed) (ExternalCreation, error) {
|
||||
return e.CreateFn(ctx, mg)
|
||||
}
|
||||
|
||||
// Update the external resource represented by the supplied Managed resource, if
|
||||
// necessary.
|
||||
func (e TypedExternalClientFns[managed]) Update(ctx context.Context, mg managed) (ExternalUpdate, error) {
|
||||
func (e ExternalClientFns) Update(ctx context.Context, mg resource.Managed) (ExternalUpdate, error) {
|
||||
return e.UpdateFn(ctx, mg)
|
||||
}
|
||||
|
||||
// Delete the external resource upon deletion of its associated Managed
|
||||
// resource.
|
||||
func (e TypedExternalClientFns[managed]) Delete(ctx context.Context, mg managed) (ExternalDelete, error) {
|
||||
func (e ExternalClientFns) Delete(ctx context.Context, mg resource.Managed) error {
|
||||
return e.DeleteFn(ctx, mg)
|
||||
}
|
||||
|
||||
// Disconnect the external client.
|
||||
func (e TypedExternalClientFns[managed]) Disconnect(ctx context.Context) error {
|
||||
return e.DisconnectFn(ctx)
|
||||
}
|
||||
|
||||
// A NopConnector does nothing.
|
||||
type NopConnector struct{}
|
||||
// A NopConnecter does nothing.
|
||||
type NopConnecter struct{}
|
||||
|
||||
// Connect returns a NopClient. It never returns an error.
|
||||
func (c *NopConnector) Connect(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
func (c *NopConnecter) Connect(_ context.Context, _ resource.Managed) (ExternalClient, error) {
|
||||
return &NopClient{}, nil
|
||||
}
|
||||
|
||||
|
@ -443,12 +392,7 @@ func (c *NopClient) Update(_ context.Context, _ resource.Managed) (ExternalUpdat
|
|||
}
|
||||
|
||||
// Delete does nothing. It never returns an error.
|
||||
func (c *NopClient) Delete(_ context.Context, _ resource.Managed) (ExternalDelete, error) {
|
||||
return ExternalDelete{}, nil
|
||||
}
|
||||
|
||||
// Disconnect does nothing. It never returns an error.
|
||||
func (c *NopClient) Disconnect(_ context.Context) error { return nil }
|
||||
func (c *NopClient) Delete(_ context.Context, _ resource.Managed) error { return nil }
|
||||
|
||||
// An ExternalObservation is the result of an observation of an external
|
||||
// resource.
|
||||
|
@ -504,10 +448,6 @@ type ExternalCreation struct {
|
|||
// unless an existing key is overwritten. Crossplane may publish these
|
||||
// credentials to a store (e.g. a Secret).
|
||||
ConnectionDetails ConnectionDetails
|
||||
|
||||
// AdditionalDetails represent any additional details the external client
|
||||
// wants to return about the creation operation that was performed.
|
||||
AdditionalDetails AdditionalDetails
|
||||
}
|
||||
|
||||
// An ExternalUpdate is the result of an update to an external resource.
|
||||
|
@ -518,17 +458,6 @@ type ExternalUpdate struct {
|
|||
// unless an existing key is overwritten. Crossplane may publish these
|
||||
// credentials to a store (e.g. a Secret).
|
||||
ConnectionDetails ConnectionDetails
|
||||
|
||||
// AdditionalDetails represent any additional details the external client
|
||||
// wants to return about the update operation that was performed.
|
||||
AdditionalDetails AdditionalDetails
|
||||
}
|
||||
|
||||
// An ExternalDelete is the result of a deletion of an external resource.
|
||||
type ExternalDelete struct {
|
||||
// AdditionalDetails represent any additional details the external client
|
||||
// wants to return about the delete operation that was performed.
|
||||
AdditionalDetails AdditionalDetails
|
||||
}
|
||||
|
||||
// A Reconciler reconciles managed resources by creating and managing the
|
||||
|
@ -554,15 +483,10 @@ type Reconciler struct {
|
|||
external mrExternal
|
||||
managed mrManaged
|
||||
|
||||
conditions conditions.Manager
|
||||
|
||||
supportedManagementPolicies []sets.Set[xpv1.ManagementAction]
|
||||
|
||||
log logging.Logger
|
||||
record event.Recorder
|
||||
metricRecorder MetricRecorder
|
||||
change ChangeLogger
|
||||
deterministicExternalName bool
|
||||
log logging.Logger
|
||||
record event.Recorder
|
||||
}
|
||||
|
||||
type mrManaged struct {
|
||||
|
@ -587,12 +511,12 @@ func defaultMRManaged(m manager.Manager) mrManaged {
|
|||
}
|
||||
|
||||
type mrExternal struct {
|
||||
ExternalConnectDisconnector
|
||||
ExternalConnectDisconnecter
|
||||
}
|
||||
|
||||
func defaultMRExternal() mrExternal {
|
||||
return mrExternal{
|
||||
ExternalConnectDisconnector: NewNopDisconnector(&NopConnector{}),
|
||||
ExternalConnectDisconnecter: NewNopDisconnecter(&NopConnecter{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,13 +544,6 @@ func WithPollInterval(after time.Duration) ReconcilerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithMetricRecorder configures the Reconciler to use the supplied MetricRecorder.
|
||||
func WithMetricRecorder(recorder MetricRecorder) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.metricRecorder = recorder
|
||||
}
|
||||
}
|
||||
|
||||
// PollIntervalHook represents the function type passed to the
|
||||
// WithPollIntervalHook option to support dynamic computation of the poll
|
||||
// interval.
|
||||
|
@ -652,8 +569,8 @@ func WithPollIntervalHook(hook PollIntervalHook) ReconcilerOption {
|
|||
// +jitter. This option wraps WithPollIntervalHook, and is subject to the same
|
||||
// constraint that only the latest hook will be used.
|
||||
func WithPollJitterHook(jitter time.Duration) ReconcilerOption {
|
||||
return WithPollIntervalHook(func(_ resource.Managed, pollInterval time.Duration) time.Duration {
|
||||
return pollInterval + time.Duration((rand.Float64()-0.5)*2*float64(jitter)) //nolint:gosec // No need for secure randomness.
|
||||
return WithPollIntervalHook(func(managed resource.Managed, pollInterval time.Duration) time.Duration {
|
||||
return pollInterval + time.Duration((rand.Float64()-0.5)*2*float64(jitter)) //#nosec G404 -- no need for secure randomness
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -668,21 +585,19 @@ func WithCreationGracePeriod(d time.Duration) ReconcilerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithExternalConnector specifies how the Reconciler should connect to the API
|
||||
// WithExternalConnecter specifies how the Reconciler should connect to the API
|
||||
// used to sync and delete external resources.
|
||||
func WithExternalConnector(c ExternalConnector) ReconcilerOption {
|
||||
func WithExternalConnecter(c ExternalConnecter) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = NewNopDisconnector(c)
|
||||
r.external.ExternalConnectDisconnecter = NewNopDisconnecter(c)
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnector specifies how the Reconciler should connect to the API
|
||||
// WithExternalConnectDisconnecter specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
func WithTypedExternalConnector[managed resource.Managed](c TypedExternalConnector[managed]) ReconcilerOption {
|
||||
func WithExternalConnectDisconnecter(c ExternalConnectDisconnecter) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = &typedExternalConnectDisconnectorWrapper[managed]{
|
||||
c: NewTypedNopDisconnector(c),
|
||||
}
|
||||
r.external.ExternalConnectDisconnecter = c
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -757,27 +672,6 @@ func WithReconcilerSupportedManagementPolicies(supported []sets.Set[xpv1.Managem
|
|||
}
|
||||
}
|
||||
|
||||
// WithChangeLogger enables support for capturing change logs during
|
||||
// reconciliation.
|
||||
func WithChangeLogger(c ChangeLogger) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.change = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithDeterministicExternalName specifies that the external name of the MR is
|
||||
// deterministic. If this value is not "true", the provider will not re-queue the
|
||||
// managed resource in scenarios where creation is deemed incomplete. This behaviour
|
||||
// is a safeguard to avoid a leaked resource due to a non-deterministic name generated
|
||||
// by the external system. Conversely, if this value is "true", signifying that the
|
||||
// managed resources is deterministically named by the external system, then this
|
||||
// safeguard is ignored as it is safe to re-queue a deterministically named resource.
|
||||
func WithDeterministicExternalName(b bool) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.deterministicExternalName = b
|
||||
}
|
||||
}
|
||||
|
||||
// NewReconciler returns a Reconciler that reconciles managed resources of the
|
||||
// supplied ManagedKind with resources in an external system such as a cloud
|
||||
// provider API. It panics if asked to reconcile a managed resource kind that is
|
||||
|
@ -787,7 +681,6 @@ func WithDeterministicExternalName(b bool) ReconcilerOption {
|
|||
// capable of managing resources in a real system.
|
||||
func NewReconciler(m manager.Manager, of resource.ManagedKind, o ...ReconcilerOption) *Reconciler {
|
||||
nm := func() resource.Managed {
|
||||
//nolint:forcetypeassert // If this isn't an MR it's a programming error and we want to panic.
|
||||
return resource.MustCreateObject(schema.GroupVersionKind(of), m.GetScheme()).(resource.Managed)
|
||||
}
|
||||
|
||||
|
@ -807,9 +700,6 @@ func NewReconciler(m manager.Manager, of resource.ManagedKind, o ...ReconcilerOp
|
|||
supportedManagementPolicies: defaultSupportedManagementPolicies(),
|
||||
log: logging.NewNopLogger(),
|
||||
record: event.NewNopRecorder(),
|
||||
metricRecorder: NewNopMetricRecorder(),
|
||||
change: newNopChangeLogger(),
|
||||
conditions: new(conditions.ObservedGenerationPropagationManager),
|
||||
}
|
||||
|
||||
for _, ro := range o {
|
||||
|
@ -820,7 +710,7 @@ func NewReconciler(m manager.Manager, of resource.ManagedKind, o ...ReconcilerOp
|
|||
}
|
||||
|
||||
// Reconcile a managed resource with an external resource.
|
||||
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (result reconcile.Result, err error) { //nolint:gocognit // See note below.
|
||||
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (result reconcile.Result, err error) { //nolint:gocyclo // See note below.
|
||||
// NOTE(negz): This method is a well over our cyclomatic complexity goal.
|
||||
// Be wary of adding additional complexity.
|
||||
|
||||
|
@ -832,8 +722,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
ctx, cancel := context.WithTimeout(ctx, r.timeout+reconcileGracePeriod)
|
||||
defer cancel()
|
||||
|
||||
externalCtx, externalCancel := context.WithTimeout(ctx, r.timeout)
|
||||
defer externalCancel()
|
||||
// Govet linter has a check for lost cancel funcs but it's a false positive
|
||||
// for child contexts as because parent's cancel is called, so we skip it
|
||||
// for this line.
|
||||
externalCtx, _ := context.WithTimeout(ctx, r.timeout) //nolint:govet // See note above.
|
||||
|
||||
managed := r.newManaged()
|
||||
if err := r.client.Get(ctx, req.NamespacedName, managed); err != nil {
|
||||
|
@ -843,9 +735,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{}, errors.Wrap(resource.IgnoreNotFound(err), errGetManaged)
|
||||
}
|
||||
|
||||
r.metricRecorder.recordFirstTimeReconciled(managed)
|
||||
status := r.conditions.For(managed)
|
||||
|
||||
record := r.record.WithAnnotations("external-name", meta.GetExternalName(managed))
|
||||
log = log.WithValues(
|
||||
"uid", managed.GetUID(),
|
||||
|
@ -870,7 +759,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
log.Debug("Reconciliation is paused either through the `spec.managementPolicies` or the pause annotation", "annotation", meta.AnnotationKeyReconciliationPaused)
|
||||
record.Event(managed, event.Normal(reasonReconciliationPaused, "Reconciliation is paused either through the `spec.managementPolicies` or the pause annotation",
|
||||
"annotation", meta.AnnotationKeyReconciliationPaused))
|
||||
status.MarkConditions(xpv1.ReconcilePaused())
|
||||
managed.SetConditions(xpv1.ReconcilePaused())
|
||||
// if the pause annotation is removed or the management policies changed, we will have a chance to reconcile
|
||||
// again and resume and if status update fails, we will reconcile again to retry to update the status
|
||||
return reconcile.Result{}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
|
@ -890,7 +779,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonManagementPolicyInvalid, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.ReconcileError(err))
|
||||
return reconcile.Result{}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -915,7 +804,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotUnpublish, err))
|
||||
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
if err := r.managed.RemoveFinalizer(ctx, managed); err != nil {
|
||||
|
@ -927,7 +816,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
if kerrors.IsConflict(err) {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -935,7 +824,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// details and removed our finalizer. If we assume we were the only
|
||||
// controller that added a finalizer to this resource then it should no
|
||||
// longer exist and thus there is no point trying to update its status.
|
||||
r.metricRecorder.recordDeleted(managed)
|
||||
log.Debug("Successfully deleted managed resource")
|
||||
return reconcile.Result{Requeue: false}, nil
|
||||
}
|
||||
|
@ -949,23 +837,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotInitialize, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
// If we started but never completed creation of an external resource we
|
||||
// may have lost critical information. For example if we didn't persist
|
||||
// an updated external name which is non-deterministic, we have leaked a
|
||||
// resource. The safest thing to do is to refuse to proceed. However, if
|
||||
// the resource has a deterministic external name, it is safe to proceed.
|
||||
// an updated external name we've leaked a resource. The safest thing to
|
||||
// do is to refuse to proceed.
|
||||
if meta.ExternalCreateIncomplete(managed) {
|
||||
if !r.deterministicExternalName {
|
||||
log.Debug(errCreateIncomplete)
|
||||
record.Event(managed, event.Warning(reasonCannotInitialize, errors.New(errCreateIncomplete)))
|
||||
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.New(errCreateIncomplete)))
|
||||
return reconcile.Result{Requeue: false}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
log.Debug("Cannot determine creation result, but proceeding due to deterministic external name")
|
||||
log.Debug(errCreateIncomplete)
|
||||
record.Event(managed, event.Warning(reasonCannotInitialize, errors.New(errCreateIncomplete)))
|
||||
managed.SetConditions(xpv1.Creating(), xpv1.ReconcileError(errors.New(errCreateIncomplete)))
|
||||
return reconcile.Result{Requeue: false}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
// We resolve any references before observing our external resource because
|
||||
|
@ -989,7 +873,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotResolveRefs, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
}
|
||||
|
@ -1006,7 +890,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotConnect, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileConnect)))
|
||||
managed.SetConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileConnect)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
defer func() {
|
||||
|
@ -1014,11 +898,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
log.Debug("Cannot disconnect from provider", "error", err)
|
||||
record.Event(managed, event.Warning(reasonCannotDisconnect, err))
|
||||
}
|
||||
|
||||
if err := external.Disconnect(ctx); err != nil {
|
||||
log.Debug("Cannot disconnect from provider", "error", err)
|
||||
record.Event(managed, event.Warning(reasonCannotDisconnect, err))
|
||||
}
|
||||
}()
|
||||
|
||||
observation, err := external.Observe(externalCtx, managed)
|
||||
|
@ -1034,7 +913,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotObserve, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileObserve)))
|
||||
managed.SetConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileObserve)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1042,7 +921,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// case, and we will explicitly return this information to the user.
|
||||
if !observation.ResourceExists && policy.ShouldOnlyObserve() {
|
||||
record.Event(managed, event.Warning(reasonCannotObserve, errors.New(errExternalResourceNotExist)))
|
||||
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(errors.New(errExternalResourceNotExist), errReconcileObserve)))
|
||||
managed.SetConditions(xpv1.ReconcileError(errors.Wrap(errors.New(errExternalResourceNotExist), errReconcileObserve)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1057,18 +936,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
|
||||
// deep copy the managed resource now that we've called Observe() and have
|
||||
// not performed any external operations - we can use this as the
|
||||
// pre-operation managed resource state in the change logs later
|
||||
//nolint:forcetypeassert // managed.DeepCopyObject() will always be a resource.Managed.
|
||||
managedPreOp := managed.DeepCopyObject().(resource.Managed)
|
||||
|
||||
if meta.WasDeleted(managed) {
|
||||
log = log.WithValues("deletion-timestamp", managed.GetDeletionTimestamp())
|
||||
|
||||
if observation.ResourceExists && policy.ShouldDelete() {
|
||||
deletion, err := external.Delete(externalCtx, managed)
|
||||
if err != nil {
|
||||
if err := external.Delete(externalCtx, managed); err != nil {
|
||||
// We'll hit this condition if we can't delete our external
|
||||
// resource, for example if our provider credentials don't have
|
||||
// access to delete it. If this is the first time we encounter
|
||||
|
@ -1076,11 +948,8 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// status with the new error condition. If not, we want requeue
|
||||
// explicitly, which will trigger backoff.
|
||||
log.Debug("Cannot delete external resource", "error", err)
|
||||
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_DELETE, err, deletion.AdditionalDetails); err != nil {
|
||||
log.Info(errRecordChangeLog, "error", err)
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotDelete, err))
|
||||
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(errors.Wrap(err, errReconcileDelete)))
|
||||
managed.SetConditions(xpv1.Deleting(), xpv1.ReconcileError(errors.Wrap(err, errReconcileDelete)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1092,11 +961,8 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// unpublish and finalize. If it still exists we'll re-enter this
|
||||
// block and try again.
|
||||
log.Debug("Successfully requested deletion of external resource")
|
||||
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_DELETE, nil, deletion.AdditionalDetails); err != nil {
|
||||
log.Info(errRecordChangeLog, "error", err)
|
||||
}
|
||||
record.Event(managed, event.Normal(reasonDeleted, "Successfully requested deletion of external resource"))
|
||||
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileSuccess())
|
||||
managed.SetConditions(xpv1.Deleting(), xpv1.ReconcileSuccess())
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
if err := r.managed.UnpublishConnection(ctx, managed, observation.ConnectionDetails); err != nil {
|
||||
|
@ -1109,7 +975,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotUnpublish, err))
|
||||
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
if err := r.managed.RemoveFinalizer(ctx, managed); err != nil {
|
||||
|
@ -1121,7 +987,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
if kerrors.IsConflict(err) {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
status.MarkConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.Deleting(), xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1129,7 +995,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// removed our finalizer. If we assume we were the only controller that
|
||||
// added a finalizer to this resource then it should no longer exist and
|
||||
// thus there is no point trying to update its status.
|
||||
r.metricRecorder.recordDeleted(managed)
|
||||
log.Debug("Successfully deleted managed resource")
|
||||
return reconcile.Result{Requeue: false}, nil
|
||||
}
|
||||
|
@ -1143,7 +1008,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotPublish, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1155,7 +1020,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
if kerrors.IsConflict(err) {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
status.MarkConditions(xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1039,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotUpdateManaged, errors.Wrap(err, errUpdateManaged)))
|
||||
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errUpdateManaged)))
|
||||
managed.SetConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errUpdateManaged)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1186,9 +1051,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// issue we'll be requeued implicitly when we update our status with
|
||||
// the new error condition. If not, we requeue explicitly, which will trigger backoff.
|
||||
log.Debug("Cannot create external resource", "error", err)
|
||||
if !kerrors.IsConflict(err) {
|
||||
record.Event(managed, event.Warning(reasonCannotCreate, err))
|
||||
if kerrors.IsConflict(err) {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotCreate, err))
|
||||
|
||||
// We handle annotations specially here because it's
|
||||
// critical that they are persisted to the API server.
|
||||
|
@ -1208,10 +1074,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// create failed.
|
||||
}
|
||||
|
||||
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_CREATE, err, creation.AdditionalDetails); err != nil {
|
||||
log.Info(errRecordChangeLog, "error", err)
|
||||
}
|
||||
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errReconcileCreate)))
|
||||
managed.SetConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errReconcileCreate)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1219,10 +1082,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
log = log.WithValues("external-name", meta.GetExternalName(managed))
|
||||
record = r.record.WithAnnotations("external-name", meta.GetExternalName(managed))
|
||||
|
||||
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_CREATE, nil, creation.AdditionalDetails); err != nil {
|
||||
log.Info(errRecordChangeLog, "error", err)
|
||||
}
|
||||
|
||||
// We handle annotations specially here because it's critical
|
||||
// that they are persisted to the API server. If we don't remove
|
||||
// add the external-create-succeeded annotation the reconciler
|
||||
|
@ -1240,7 +1099,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotUpdateManaged, errors.Wrap(err, errUpdateManagedAnnotations)))
|
||||
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errUpdateManagedAnnotations)))
|
||||
managed.SetConditions(xpv1.Creating(), xpv1.ReconcileError(errors.Wrap(err, errUpdateManagedAnnotations)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1112,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotPublish, err))
|
||||
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.Creating(), xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1263,7 +1122,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// ready for use.
|
||||
log.Debug("Successfully requested creation of external resource")
|
||||
record.Event(managed, event.Normal(reasonCreated, "Successfully requested creation of external resource"))
|
||||
status.MarkConditions(xpv1.Creating(), xpv1.ReconcileSuccess())
|
||||
managed.SetConditions(xpv1.Creating(), xpv1.ReconcileSuccess())
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1278,7 +1137,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
if err := r.client.Update(ctx, managed); err != nil {
|
||||
log.Debug(errUpdateManaged, "error", err)
|
||||
record.Event(managed, event.Warning(reasonCannotUpdateManaged, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errUpdateManaged)))
|
||||
managed.SetConditions(xpv1.ReconcileError(errors.Wrap(err, errUpdateManaged)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
}
|
||||
|
@ -1292,15 +1151,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// https://github.com/crossplane/crossplane/issues/289
|
||||
reconcileAfter := r.pollIntervalHook(managed, r.pollInterval)
|
||||
log.Debug("External resource is up to date", "requeue-after", time.Now().Add(reconcileAfter))
|
||||
status.MarkConditions(xpv1.ReconcileSuccess())
|
||||
r.metricRecorder.recordFirstTimeReady(managed)
|
||||
|
||||
// record that we intentionally did not update the managed resource
|
||||
// because no drift was detected. We call this so late in the reconcile
|
||||
// because all the cases above could contribute (for different reasons)
|
||||
// that the external object would not have been updated.
|
||||
r.metricRecorder.recordUnchanged(managed.GetName())
|
||||
|
||||
managed.SetConditions(xpv1.ReconcileSuccess())
|
||||
return reconcile.Result{RequeueAfter: reconcileAfter}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1312,7 +1163,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
if !policy.ShouldUpdate() {
|
||||
reconcileAfter := r.pollIntervalHook(managed, r.pollInterval)
|
||||
log.Debug("Skipping update due to managementPolicies. Reconciliation succeeded", "requeue-after", time.Now().Add(reconcileAfter))
|
||||
status.MarkConditions(xpv1.ReconcileSuccess())
|
||||
managed.SetConditions(xpv1.ReconcileSuccess())
|
||||
return reconcile.Result{RequeueAfter: reconcileAfter}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1324,27 +1175,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
// requeued implicitly when we update our status with the new error
|
||||
// condition. If not, we requeue explicitly, which will trigger backoff.
|
||||
log.Debug("Cannot update external resource")
|
||||
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_UPDATE, err, update.AdditionalDetails); err != nil {
|
||||
log.Info(errRecordChangeLog, "error", err)
|
||||
}
|
||||
record.Event(managed, event.Warning(reasonCannotUpdate, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileUpdate)))
|
||||
managed.SetConditions(xpv1.ReconcileError(errors.Wrap(err, errReconcileUpdate)))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
// record the drift after the successful update.
|
||||
r.metricRecorder.recordDrift(managed)
|
||||
if err := r.change.Log(ctx, managedPreOp, v1alpha1.OperationType_OPERATION_TYPE_UPDATE, nil, update.AdditionalDetails); err != nil {
|
||||
log.Info(errRecordChangeLog, "error", err)
|
||||
}
|
||||
|
||||
if _, err := r.managed.PublishConnection(ctx, managed, update.ConnectionDetails); err != nil {
|
||||
// If this is the first time we encounter this issue we'll be requeued
|
||||
// implicitly when we update our status with the new error condition. If
|
||||
// not, we requeue explicitly, which will trigger backoff.
|
||||
log.Debug("Cannot publish connection details", "error", err)
|
||||
record.Event(managed, event.Warning(reasonCannotPublish, err))
|
||||
status.MarkConditions(xpv1.ReconcileError(err))
|
||||
managed.SetConditions(xpv1.ReconcileError(err))
|
||||
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
||||
|
@ -1356,6 +1198,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
|
|||
reconcileAfter := r.pollIntervalHook(managed, r.pollInterval)
|
||||
log.Debug("Successfully requested update of external resource", "requeue-after", time.Now().Add(reconcileAfter))
|
||||
record.Event(managed, event.Normal(reasonUpdated, "Successfully requested update of external resource"))
|
||||
status.MarkConditions(xpv1.ReconcileSuccess())
|
||||
managed.SetConditions(xpv1.ReconcileSuccess())
|
||||
return reconcile.Result{RequeueAfter: reconcileAfter}, errors.Wrap(r.client.Status().Update(ctx, managed), errUpdateManagedStatus)
|
||||
}
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
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 managed
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
)
|
||||
|
||||
// ExternalConnecter an alias to ExternalConnector.
|
||||
// Deprecated: use ExternalConnector.
|
||||
type ExternalConnecter = ExternalConnector
|
||||
|
||||
// TypedExternalConnecter an alias to TypedExternalConnector.
|
||||
// Deprecated: use TypedExternalConnector.
|
||||
type TypedExternalConnecter[managed resource.Managed] interface {
|
||||
TypedExternalConnector[managed]
|
||||
}
|
||||
|
||||
// An ExternalDisconnector disconnects from a provider.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting
|
||||
// from the provider.
|
||||
//
|
||||
//nolint:iface // We know it is a redundant interface.
|
||||
type ExternalDisconnector interface {
|
||||
// Disconnect from the provider and close the ExternalClient.
|
||||
Disconnect(ctx context.Context) error
|
||||
}
|
||||
|
||||
// ExternalDisconnecter an alias to ExternalDisconnector.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting
|
||||
// from the provider.
|
||||
//
|
||||
//nolint:iface // We know it is a redundant interface
|
||||
type ExternalDisconnecter interface {
|
||||
ExternalDisconnector
|
||||
}
|
||||
|
||||
// NopDisconnecter aliases NopDisconnector.
|
||||
// Deprecated: Use NopDisconnector.
|
||||
type NopDisconnecter = NopDisconnector
|
||||
|
||||
// TODO: these types of aliases are only allowed in Go 1.23 and above.
|
||||
// type TypedNopDisconnecter[managed resource.Managed] = TypedNopDisconnector[managed]
|
||||
// type TypedNopDisconnecter[managed resource.Managed] = TypedNopDisconnector[managed]
|
||||
// type TypedExternalConnectDisconnecterFns[managed resource.Managed] = TypedExternalConnectDisconnectorFns[managed]
|
||||
|
||||
// NewNopDisconnecter an alias to NewNopDisconnector.
|
||||
// Deprecated: use NewNopDisconnector.
|
||||
func NewNopDisconnecter(c ExternalConnector) ExternalConnectDisconnector {
|
||||
return NewNopDisconnector(c)
|
||||
}
|
||||
|
||||
// ExternalDisconnecterFn aliases ExternalDisconnectorFn.
|
||||
// Deprecated: use ExternalDisconnectorFn.
|
||||
type ExternalDisconnecterFn = ExternalDisconnectorFn
|
||||
|
||||
// ExternalConnectDisconnecterFns aliases ExternalConnectDisconnectorFns.
|
||||
// Deprecated: use ExternalConnectDisconnectorFns.
|
||||
type ExternalConnectDisconnecterFns = ExternalConnectDisconnectorFns
|
||||
|
||||
// NopConnecter aliases NopConnector.
|
||||
// Deprecated: use NopConnector.
|
||||
type NopConnecter = NopConnector
|
||||
|
||||
// WithExternalConnecter aliases WithExternalConnector.
|
||||
// Deprecated: use WithExternalConnector.
|
||||
func WithExternalConnecter(c ExternalConnector) ReconcilerOption {
|
||||
return WithExternalConnector(c)
|
||||
}
|
||||
|
||||
// WithExternalConnectDisconnector specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithExternalConnectDisconnector(c ExternalConnectDisconnector) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithExternalConnectDisconnecter aliases WithExternalConnectDisconnector.
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithExternalConnectDisconnecter(c ExternalConnectDisconnector) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnectDisconnector specifies how the Reconciler should connect and disconnect to the API
|
||||
// used to sync and delete external resources.
|
||||
//
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithTypedExternalConnectDisconnector[managed resource.Managed](c TypedExternalConnectDisconnector[managed]) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = &typedExternalConnectDisconnectorWrapper[managed]{c}
|
||||
}
|
||||
}
|
||||
|
||||
// WithTypedExternalConnectDisconnecter aliases WithTypedExternalConnectDisconnector.
|
||||
// Deprecated: Please use Disconnect() on the ExternalClient for disconnecting from the provider.
|
||||
func WithTypedExternalConnectDisconnecter[managed resource.Managed](c TypedExternalConnectDisconnector[managed]) ReconcilerOption {
|
||||
return func(r *Reconciler) {
|
||||
r.external.ExternalConnectDisconnector = &typedExternalConnectDisconnectorWrapper[managed]{c}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,74 +0,0 @@
|
|||
package managed
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
||||
)
|
||||
|
||||
const errFmtUnexpectedObjectType = "unexpected object type %T"
|
||||
|
||||
// typedExternalConnectDisconnectorWrapper wraps a TypedExternalConnector to a
|
||||
// common ExternalConnector.
|
||||
type typedExternalConnectDisconnectorWrapper[managed resource.Managed] struct {
|
||||
c TypedExternalConnectDisconnector[managed]
|
||||
}
|
||||
|
||||
func (c *typedExternalConnectDisconnectorWrapper[managed]) Connect(ctx context.Context, mg resource.Managed) (ExternalClient, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
return nil, errors.Errorf(errFmtUnexpectedObjectType, mg)
|
||||
}
|
||||
external, err := c.c.Connect(ctx, cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &typedExternalClientWrapper[managed]{c: external}, nil
|
||||
}
|
||||
|
||||
func (c *typedExternalConnectDisconnectorWrapper[managed]) Disconnect(ctx context.Context) error {
|
||||
return c.c.Disconnect(ctx)
|
||||
}
|
||||
|
||||
// typedExternalClientWrapper wraps a TypedExternalClient to a common
|
||||
// ExternalClient.
|
||||
type typedExternalClientWrapper[managed resource.Managed] struct {
|
||||
c TypedExternalClient[managed]
|
||||
}
|
||||
|
||||
func (c *typedExternalClientWrapper[managed]) Observe(ctx context.Context, mg resource.Managed) (ExternalObservation, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
return ExternalObservation{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
|
||||
}
|
||||
return c.c.Observe(ctx, cr)
|
||||
}
|
||||
|
||||
func (c *typedExternalClientWrapper[managed]) Create(ctx context.Context, mg resource.Managed) (ExternalCreation, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
return ExternalCreation{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
|
||||
}
|
||||
return c.c.Create(ctx, cr)
|
||||
}
|
||||
|
||||
func (c *typedExternalClientWrapper[managed]) Update(ctx context.Context, mg resource.Managed) (ExternalUpdate, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
return ExternalUpdate{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
|
||||
}
|
||||
return c.c.Update(ctx, cr)
|
||||
}
|
||||
|
||||
func (c *typedExternalClientWrapper[managed]) Delete(ctx context.Context, mg resource.Managed) (ExternalDelete, error) {
|
||||
cr, ok := mg.(managed)
|
||||
if !ok {
|
||||
return ExternalDelete{}, errors.Errorf(errFmtUnexpectedObjectType, mg)
|
||||
}
|
||||
return c.c.Delete(ctx, cr)
|
||||
}
|
||||
|
||||
func (c *typedExternalClientWrapper[managed]) Disconnect(ctx context.Context) error {
|
||||
return c.c.Disconnect(ctx)
|
||||
}
|
|
@ -111,11 +111,9 @@ func WithRecorder(er event.Recorder) ReconcilerOption {
|
|||
// NewReconciler returns a Reconciler of ProviderConfigs.
|
||||
func NewReconciler(m manager.Manager, of resource.ProviderConfigKinds, o ...ReconcilerOption) *Reconciler {
|
||||
nc := func() resource.ProviderConfig {
|
||||
//nolint:forcetypeassert // If this isn't a ProviderConfig it's a programming error and we want to panic.
|
||||
return resource.MustCreateObject(of.Config, m.GetScheme()).(resource.ProviderConfig)
|
||||
}
|
||||
nul := func() resource.ProviderConfigUsageList {
|
||||
//nolint:forcetypeassert // If this isn't a ProviderConfigUsage it's a programming error and we want to panic.
|
||||
return resource.MustCreateObject(of.UsageList, m.GetScheme()).(resource.ProviderConfigUsageList)
|
||||
}
|
||||
|
||||
|
@ -181,7 +179,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
|
|||
if err := r.client.Delete(ctx, pcu); resource.IgnoreNotFound(err) != nil {
|
||||
log.Debug(errDeletePCU, "error", err)
|
||||
r.record.Event(pc, event.Warning(reasonAccount, errors.Wrap(err, errDeletePCU)))
|
||||
return reconcile.Result{RequeueAfter: shortWait}, nil
|
||||
return reconcile.Result{RequeueAfter: shortWait}, nil //nolint:nilerr // Returning err would make us requeue instantly.
|
||||
}
|
||||
users--
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import (
|
|||
|
||||
// This can't live in fake, because it would cause an import cycle due to
|
||||
// GetItems returning managed.ProviderConfigUsage.
|
||||
type ProviderConfigUsageList struct {
|
||||
type ProviderConfigUsageList struct { //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
client.ObjectList
|
||||
Items []resource.ProviderConfigUsage
|
||||
}
|
||||
|
@ -50,11 +50,11 @@ func (p *ProviderConfigUsageList) GetObjectKind() schema.ObjectKind {
|
|||
|
||||
func (p *ProviderConfigUsageList) DeepCopyObject() runtime.Object {
|
||||
out := &ProviderConfigUsageList{}
|
||||
j, err := json.Marshal(p) //nolint:musttag // We're just using this to round-trip convert.
|
||||
j, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = json.Unmarshal(j, out) //nolint:musttag // We're just using this to round-trip convert.
|
||||
_ = json.Unmarshal(j, out)
|
||||
return out
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ package reference
|
|||
|
||||
import (
|
||||
"context"
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -62,14 +60,6 @@ func FromFloatPtrValue(v *float64) string {
|
|||
return strconv.FormatFloat(*v, 'f', 0, 64)
|
||||
}
|
||||
|
||||
// FromIntPtrValue adapts an int pointer field for use as a CurrentValue.
|
||||
func FromIntPtrValue(v *int64) string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatInt(*v, 10)
|
||||
}
|
||||
|
||||
// ToPtrValue adapts a ResolvedValue for use as a string pointer field.
|
||||
func ToPtrValue(v string) *string {
|
||||
if v == "" {
|
||||
|
@ -90,26 +80,14 @@ func ToFloatPtrValue(v string) *float64 {
|
|||
return &vParsed
|
||||
}
|
||||
|
||||
// ToIntPtrValue adapts a ResolvedValue for use as an int pointer field.
|
||||
func ToIntPtrValue(v string) *int64 {
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
vParsed, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &vParsed
|
||||
}
|
||||
|
||||
// FromPtrValues adapts a slice of string pointer fields for use as CurrentValues.
|
||||
// NOTE: Do not use this utility function unless you have to.
|
||||
// Using pointer slices does not adhere to our current API practices.
|
||||
// The current use case is where generated code creates reference-able fields in a provider which are
|
||||
// string pointers and need to be resolved as part of `ResolveMultiple`.
|
||||
// string pointers and need to be resolved as part of `ResolveMultiple`
|
||||
func FromPtrValues(v []*string) []string {
|
||||
res := make([]string, len(v))
|
||||
for i := range v {
|
||||
var res = make([]string, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
res[i] = FromPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -117,30 +95,21 @@ func FromPtrValues(v []*string) []string {
|
|||
|
||||
// FromFloatPtrValues adapts a slice of float64 pointer fields for use as CurrentValues.
|
||||
func FromFloatPtrValues(v []*float64) []string {
|
||||
res := make([]string, len(v))
|
||||
for i := range v {
|
||||
var res = make([]string, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
res[i] = FromFloatPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// FromIntPtrValues adapts a slice of int64 pointer fields for use as CurrentValues.
|
||||
func FromIntPtrValues(v []*int64) []string {
|
||||
res := make([]string, len(v))
|
||||
for i := range v {
|
||||
res[i] = FromIntPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ToPtrValues adapts ResolvedValues for use as a slice of string pointer fields.
|
||||
// NOTE: Do not use this utility function unless you have to.
|
||||
// Using pointer slices does not adhere to our current API practices.
|
||||
// The current use case is where generated code creates reference-able fields in a provider which are
|
||||
// string pointers and need to be resolved as part of `ResolveMultiple`.
|
||||
// string pointers and need to be resolved as part of `ResolveMultiple`
|
||||
func ToPtrValues(v []string) []*string {
|
||||
res := make([]*string, len(v))
|
||||
for i := range v {
|
||||
var res = make([]*string, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
res[i] = ToPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
|
@ -148,22 +117,13 @@ func ToPtrValues(v []string) []*string {
|
|||
|
||||
// ToFloatPtrValues adapts ResolvedValues for use as a slice of float64 pointer fields.
|
||||
func ToFloatPtrValues(v []string) []*float64 {
|
||||
res := make([]*float64, len(v))
|
||||
for i := range v {
|
||||
var res = make([]*float64, len(v))
|
||||
for i := 0; i < len(v); i++ {
|
||||
res[i] = ToFloatPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ToIntPtrValues adapts ResolvedValues for use as a slice of int64 pointer fields.
|
||||
func ToIntPtrValues(v []string) []*int64 {
|
||||
res := make([]*int64, len(v))
|
||||
for i := range v {
|
||||
res[i] = ToIntPtrValue(v[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// To indicates the kind of managed resource a reference is to.
|
||||
type To struct {
|
||||
Managed resource.Managed
|
||||
|
@ -190,7 +150,6 @@ type ResolutionRequest struct {
|
|||
Selector *xpv1.Selector
|
||||
To To
|
||||
Extract ExtractValueFn
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// IsNoOp returns true if the supplied ResolutionRequest cannot or should not be
|
||||
|
@ -245,7 +204,6 @@ type MultiResolutionRequest struct {
|
|||
Selector *xpv1.Selector
|
||||
To To
|
||||
Extract ExtractValueFn
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// IsNoOp returns true if the supplied MultiResolutionRequest cannot or should
|
||||
|
@ -327,7 +285,7 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
|
|||
|
||||
// The reference is already set - resolve it.
|
||||
if req.Reference != nil {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.Reference.Name, Namespace: req.Namespace}, req.To.Managed); err != nil {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.Reference.Name}, req.To.Managed); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return ResolutionResponse{}, getResolutionError(req.Reference.Policy, errors.Wrap(err, errGetManaged))
|
||||
}
|
||||
|
@ -338,9 +296,8 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
|
|||
return rsp, getResolutionError(req.Reference.Policy, rsp.Validate())
|
||||
}
|
||||
|
||||
// The reference was not set, but a selector was. Select a reference. If the
|
||||
// request has no namespace, then InNamespace is a no-op.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels), client.InNamespace(req.Namespace)); err != nil {
|
||||
// The reference was not set, but a selector was. Select a reference.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels)); err != nil {
|
||||
return ResolutionResponse{}, errors.Wrap(err, errListManaged)
|
||||
}
|
||||
|
||||
|
@ -355,6 +312,7 @@ func (r *APIResolver) Resolve(ctx context.Context, req ResolutionRequest) (Resol
|
|||
|
||||
// We couldn't resolve anything.
|
||||
return ResolutionResponse{}, getResolutionError(req.Selector.Policy, errors.New(errNoMatches))
|
||||
|
||||
}
|
||||
|
||||
// ResolveMultiple resolves the supplied MultiResolutionRequest. The returned
|
||||
|
@ -366,43 +324,41 @@ func (r *APIResolver) ResolveMultiple(ctx context.Context, req MultiResolutionRe
|
|||
return MultiResolutionResponse{ResolvedValues: req.CurrentValues, ResolvedReferences: req.References}, nil
|
||||
}
|
||||
|
||||
valueMap := make(map[string]xpv1.Reference)
|
||||
|
||||
// The references are already set - resolve them.
|
||||
if len(req.References) > 0 {
|
||||
vals := make([]string, len(req.References))
|
||||
for i := range req.References {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.References[i].Name, Namespace: req.Namespace}, req.To.Managed); err != nil {
|
||||
if err := r.client.Get(ctx, types.NamespacedName{Name: req.References[i].Name}, req.To.Managed); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return MultiResolutionResponse{}, getResolutionError(req.References[i].Policy, errors.Wrap(err, errGetManaged))
|
||||
}
|
||||
return MultiResolutionResponse{}, errors.Wrap(err, errGetManaged)
|
||||
}
|
||||
valueMap[req.Extract(req.To.Managed)] = req.References[i]
|
||||
vals[i] = req.Extract(req.To.Managed)
|
||||
}
|
||||
|
||||
sortedKeys, sortedRefs := sortMapByKeys(valueMap)
|
||||
|
||||
rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
|
||||
rsp := MultiResolutionResponse{ResolvedValues: vals, ResolvedReferences: req.References}
|
||||
return rsp, rsp.Validate()
|
||||
}
|
||||
|
||||
// No references were set, but a selector was. Select and resolve
|
||||
// references. If the request has no namespace, then InNamespace is a no-op.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels), client.InNamespace(req.Namespace)); err != nil {
|
||||
// No references were set, but a selector was. Select and resolve references.
|
||||
if err := r.client.List(ctx, req.To.List, client.MatchingLabels(req.Selector.MatchLabels)); err != nil {
|
||||
return MultiResolutionResponse{}, errors.Wrap(err, errListManaged)
|
||||
}
|
||||
|
||||
items := req.To.List.GetItems()
|
||||
refs := make([]xpv1.Reference, 0, len(items))
|
||||
vals := make([]string, 0, len(items))
|
||||
for _, to := range req.To.List.GetItems() {
|
||||
if ControllersMustMatch(req.Selector) && !meta.HaveSameController(r.from, to) {
|
||||
continue
|
||||
}
|
||||
|
||||
valueMap[req.Extract(to)] = xpv1.Reference{Name: to.GetName()}
|
||||
vals = append(vals, req.Extract(to))
|
||||
refs = append(refs, xpv1.Reference{Name: to.GetName()})
|
||||
}
|
||||
|
||||
sortedKeys, sortedRefs := sortMapByKeys(valueMap)
|
||||
|
||||
rsp := MultiResolutionResponse{ResolvedValues: sortedKeys, ResolvedReferences: sortedRefs}
|
||||
rsp := MultiResolutionResponse{ResolvedValues: vals, ResolvedReferences: refs}
|
||||
return rsp, getResolutionError(req.Selector.Policy, rsp.Validate())
|
||||
}
|
||||
|
||||
|
@ -413,15 +369,6 @@ func getResolutionError(p *xpv1.Policy, err error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func sortMapByKeys(m map[string]xpv1.Reference) ([]string, []xpv1.Reference) {
|
||||
keys := slices.Sorted(maps.Keys(m))
|
||||
values := make([]xpv1.Reference, 0, len(keys))
|
||||
for _, k := range keys {
|
||||
values = append(values, m[k])
|
||||
}
|
||||
return keys, values
|
||||
}
|
||||
|
||||
// ControllersMustMatch returns true if the supplied Selector requires that a
|
||||
// reference be to a managed resource whose controller reference matches the
|
||||
// referencing resource.
|
||||
|
|
|
@ -59,8 +59,10 @@ func TestToAndFromPtr(t *testing.T) {
|
|||
got := FromPtrValue(ToPtrValue(tc.want))
|
||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||
t.Errorf("FromPtrValue(ToPtrValue(%s): -want, +got: %s", tc.want, diff)
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,8 +78,10 @@ func TestToAndFromFloatPtr(t *testing.T) {
|
|||
got := FromFloatPtrValue(ToFloatPtrValue(tc.want))
|
||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||
t.Errorf("FromPtrValue(ToPtrValue(%s): -want, +got: %s", tc.want, diff)
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,6 +99,7 @@ func TestToAndFromPtrValues(t *testing.T) {
|
|||
got := FromPtrValues(ToPtrValues(tc.want))
|
||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||
t.Errorf("FromPtrValues(ToPtrValues(%s): -want, +got: %s", tc.want, diff)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -114,25 +119,7 @@ func TestToAndFromFloatPtrValues(t *testing.T) {
|
|||
got := FromFloatPtrValues(ToFloatPtrValues(tc.want))
|
||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||
t.Errorf("FromPtrValues(ToPtrValues(%s): -want, +got: %s", tc.want, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToAndFromIntPtrValues(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
want []string
|
||||
}{
|
||||
"Nil": {want: []string{}},
|
||||
"Zero": {want: []string{""}},
|
||||
"NonZero": {want: []string{"1123581321"}},
|
||||
"Multiple": {want: []string{"1123581321", "1234567890"}},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := FromIntPtrValues(ToIntPtrValues(tc.want))
|
||||
if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||
t.Errorf("FromIntPtrValues(ToIntPtrValues(%s): -want, +got: %s", tc.want, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -286,30 +273,6 @@ func TestResolve(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"SuccessfulResolveNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
meta.SetExternalName(obj.(metav1.Object), value)
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
from: &fake.Managed{},
|
||||
args: args{
|
||||
req: ResolutionRequest{
|
||||
Reference: ref,
|
||||
To: To{Managed: &fake.Managed{}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: ResolutionResponse{
|
||||
ResolvedValue: value,
|
||||
ResolvedReference: ref,
|
||||
},
|
||||
},
|
||||
},
|
||||
"OptionalReference": {
|
||||
reason: "No error should be returned when the resolution policy is Optional",
|
||||
c: &test.MockClient{
|
||||
|
@ -408,33 +371,6 @@ func TestResolve(t *testing.T) {
|
|||
err: nil,
|
||||
},
|
||||
},
|
||||
"SuccessfulSelectNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockList: test.NewMockListFn(nil),
|
||||
},
|
||||
from: controlled,
|
||||
args: args{
|
||||
req: ResolutionRequest{
|
||||
Selector: &xpv1.Selector{
|
||||
MatchControllerRef: func() *bool { t := true; return &t }(),
|
||||
},
|
||||
To: To{List: &FakeManagedList{Items: []resource.Managed{
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled, // A resource with a matching controller reference.
|
||||
}}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: ResolutionResponse{
|
||||
ResolvedValue: value,
|
||||
ResolvedReference: &xpv1.Reference{Name: value},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"AlwaysResolveSelector": {
|
||||
reason: "Should not return early if the current value is non-zero, when the resolve policy is set to" +
|
||||
"Always",
|
||||
|
@ -504,12 +440,10 @@ func TestResolve(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveMultiple(t *testing.T) {
|
||||
errBoom := errors.New("boom")
|
||||
now := metav1.Now()
|
||||
value := "coolv"
|
||||
value2 := "cooler"
|
||||
ref := xpv1.Reference{Name: "cool"}
|
||||
optionalPolicy := xpv1.ResolutionPolicyOptional
|
||||
alwaysPolicy := xpv1.ResolvePolicyAlways
|
||||
|
@ -521,11 +455,6 @@ func TestResolveMultiple(t *testing.T) {
|
|||
meta.SetExternalName(controlled, value)
|
||||
meta.AddControllerReference(controlled, meta.AsController(&xpv1.TypedReference{UID: types.UID("very-unique")}))
|
||||
|
||||
controlled2 := &fake.Managed{}
|
||||
controlled2.SetName(value2)
|
||||
meta.SetExternalName(controlled2, value2)
|
||||
meta.AddControllerReference(controlled2, meta.AsController(&xpv1.TypedReference{UID: types.UID("very-unique")}))
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req MultiResolutionRequest
|
||||
|
@ -660,30 +589,6 @@ func TestResolveMultiple(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"SuccessfulResolveNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
|
||||
meta.SetExternalName(obj.(metav1.Object), value)
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
from: &fake.Managed{},
|
||||
args: args{
|
||||
req: MultiResolutionRequest{
|
||||
References: []xpv1.Reference{ref},
|
||||
To: To{Managed: &fake.Managed{}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: MultiResolutionResponse{
|
||||
ResolvedValues: []string{value},
|
||||
ResolvedReferences: []xpv1.Reference{ref},
|
||||
},
|
||||
},
|
||||
},
|
||||
"OptionalReference": {
|
||||
reason: "No error should be returned when the resolution policy is Optional",
|
||||
c: &test.MockClient{
|
||||
|
@ -783,33 +688,6 @@ func TestResolveMultiple(t *testing.T) {
|
|||
err: nil,
|
||||
},
|
||||
},
|
||||
"SuccessfulSelectNamespaced": {
|
||||
reason: "Resolve should be successful when a namespace is given",
|
||||
c: &test.MockClient{
|
||||
MockList: test.NewMockListFn(nil),
|
||||
},
|
||||
from: controlled,
|
||||
args: args{
|
||||
req: MultiResolutionRequest{
|
||||
Selector: &xpv1.Selector{
|
||||
MatchControllerRef: func() *bool { t := true; return &t }(),
|
||||
},
|
||||
To: To{List: &FakeManagedList{Items: []resource.Managed{
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled, // A resource with a matching controller reference.
|
||||
}}},
|
||||
Extract: ExternalName(),
|
||||
Namespace: "cool-ns",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: MultiResolutionResponse{
|
||||
ResolvedValues: []string{value},
|
||||
ResolvedReferences: []xpv1.Reference{{Name: value}},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"AlwaysResolveSelector": {
|
||||
reason: "Should not return early if the current value is non-zero, when the resolve policy is set to" +
|
||||
"Always",
|
||||
|
@ -865,36 +743,6 @@ func TestResolveMultiple(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"OrderOutput": {
|
||||
reason: "Output values should ordered",
|
||||
c: &test.MockClient{
|
||||
MockList: test.NewMockListFn(nil),
|
||||
},
|
||||
from: controlled,
|
||||
args: args{
|
||||
req: MultiResolutionRequest{
|
||||
Selector: &xpv1.Selector{
|
||||
MatchControllerRef: func() *bool { t := true; return &t }(),
|
||||
},
|
||||
To: To{List: &FakeManagedList{
|
||||
Items: []resource.Managed{
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled, // A resource with a matching controller reference.
|
||||
&fake.Managed{}, // A resource that does not match.
|
||||
controlled2, // A resource with a matching controller reference.
|
||||
},
|
||||
}},
|
||||
Extract: ExternalName(),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
rsp: MultiResolutionResponse{
|
||||
ResolvedValues: []string{value2, value},
|
||||
ResolvedReferences: []xpv1.Reference{{Name: value2}, {Name: value}},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
|
|
|
@ -110,7 +110,6 @@ func (a *APIUpdatingApplicator) Apply(ctx context.Context, o client.Object, ao .
|
|||
return errors.Wrap(a.client.Create(ctx, o), "cannot create object")
|
||||
}
|
||||
|
||||
//nolint:forcetypeassert // Will always be a client.Object.
|
||||
current := o.DeepCopyObject().(client.Object)
|
||||
|
||||
err := a.client.Get(ctx, types.NamespacedName{Name: m.GetName(), Namespace: m.GetNamespace()}, current)
|
||||
|
@ -130,7 +129,7 @@ func (a *APIUpdatingApplicator) Apply(ctx context.Context, o client.Object, ao .
|
|||
|
||||
// NOTE(hasheddan): we must set the resource version of the desired object
|
||||
// to that of the current or the update will always fail.
|
||||
m.SetResourceVersion(current.GetResourceVersion())
|
||||
m.SetResourceVersion(current.(metav1.Object).GetResourceVersion())
|
||||
return errors.Wrap(a.client.Update(ctx, m), "cannot update object")
|
||||
}
|
||||
|
||||
|
@ -148,7 +147,6 @@ type nopFinalizer struct{}
|
|||
func (f nopFinalizer) AddFinalizer(_ context.Context, _ Object) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f nopFinalizer) RemoveFinalizer(_ context.Context, _ Object) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -27,38 +27,35 @@ import (
|
|||
)
|
||||
|
||||
type adder interface {
|
||||
Add(item reconcile.Request)
|
||||
Add(item any)
|
||||
}
|
||||
|
||||
// RateLimitingInterface for an EnqueueRequestForProviderConfig.
|
||||
type RateLimitingInterface = workqueue.TypedRateLimitingInterface[reconcile.Request]
|
||||
|
||||
// EnqueueRequestForProviderConfig enqueues a reconcile.Request for a referenced
|
||||
// ProviderConfig.
|
||||
type EnqueueRequestForProviderConfig struct{}
|
||||
|
||||
// Create adds a NamespacedName for the supplied CreateEvent if its Object is a
|
||||
// ProviderConfigReferencer.
|
||||
func (e *EnqueueRequestForProviderConfig) Create(_ context.Context, evt event.CreateEvent, q RateLimitingInterface) {
|
||||
func (e *EnqueueRequestForProviderConfig) Create(_ context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
addProviderConfig(evt.Object, q)
|
||||
}
|
||||
|
||||
// Update adds a NamespacedName for the supplied UpdateEvent if its Objects are
|
||||
// a ProviderConfigReferencer.
|
||||
func (e *EnqueueRequestForProviderConfig) Update(_ context.Context, evt event.UpdateEvent, q RateLimitingInterface) {
|
||||
func (e *EnqueueRequestForProviderConfig) Update(_ context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
addProviderConfig(evt.ObjectOld, q)
|
||||
addProviderConfig(evt.ObjectNew, q)
|
||||
}
|
||||
|
||||
// Delete adds a NamespacedName for the supplied DeleteEvent if its Object is a
|
||||
// ProviderConfigReferencer.
|
||||
func (e *EnqueueRequestForProviderConfig) Delete(_ context.Context, evt event.DeleteEvent, q RateLimitingInterface) {
|
||||
func (e *EnqueueRequestForProviderConfig) Delete(_ context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
addProviderConfig(evt.Object, q)
|
||||
}
|
||||
|
||||
// Generic adds a NamespacedName for the supplied GenericEvent if its Object is
|
||||
// a ProviderConfigReferencer.
|
||||
func (e *EnqueueRequestForProviderConfig) Generic(_ context.Context, evt event.GenericEvent, q RateLimitingInterface) {
|
||||
func (e *EnqueueRequestForProviderConfig) Generic(_ context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
addProviderConfig(evt.Object, q)
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,13 @@ import (
|
|||
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
)
|
||||
|
||||
var _ handler.EventHandler = &EnqueueRequestForProviderConfig{}
|
||||
var (
|
||||
_ handler.EventHandler = &EnqueueRequestForProviderConfig{}
|
||||
)
|
||||
|
||||
type addFn func(item any)
|
||||
|
||||
func (fn addFn) Add(item reconcile.Request) {
|
||||
func (fn addFn) Add(item any) {
|
||||
fn(item)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// Package fake provides fake Crossplane resources for use in tests.
|
||||
//
|
||||
//nolint:musttag // We only use JSON to round-trip convert these mocks.
|
||||
package fake
|
||||
|
||||
import (
|
||||
|
@ -35,7 +33,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/reference"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/claim"
|
||||
)
|
||||
|
||||
// Conditioned is a mock that implements Conditioned interface.
|
||||
|
@ -50,13 +48,13 @@ func (m *Conditioned) GetCondition(ct xpv1.ConditionType) xpv1.Condition {
|
|||
}
|
||||
|
||||
// ClaimReferencer is a mock that implements ClaimReferencer interface.
|
||||
type ClaimReferencer struct{ Ref *reference.Claim }
|
||||
type ClaimReferencer struct{ Ref *claim.Reference }
|
||||
|
||||
// SetClaimReference sets the ClaimReference.
|
||||
func (m *ClaimReferencer) SetClaimReference(r *reference.Claim) { m.Ref = r }
|
||||
func (m *ClaimReferencer) SetClaimReference(r *claim.Reference) { m.Ref = r }
|
||||
|
||||
// GetClaimReference gets the ClaimReference.
|
||||
func (m *ClaimReferencer) GetClaimReference() *reference.Claim { return m.Ref }
|
||||
func (m *ClaimReferencer) GetClaimReference() *claim.Reference { return m.Ref }
|
||||
|
||||
// ManagedResourceReferencer is a mock that implements ManagedResourceReferencer interface.
|
||||
type ManagedResourceReferencer struct{ Ref *corev1.ObjectReference }
|
||||
|
@ -68,7 +66,7 @@ func (m *ManagedResourceReferencer) SetResourceReference(r *corev1.ObjectReferen
|
|||
func (m *ManagedResourceReferencer) GetResourceReference() *corev1.ObjectReference { return m.Ref }
|
||||
|
||||
// ProviderConfigReferencer is a mock that implements ProviderConfigReferencer interface.
|
||||
type ProviderConfigReferencer struct{ Ref *xpv1.Reference }
|
||||
type ProviderConfigReferencer struct{ Ref *xpv1.Reference } //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
|
||||
// SetProviderConfigReference sets the ProviderConfigReference.
|
||||
func (m *ProviderConfigReferencer) SetProviderConfigReference(p *xpv1.Reference) { m.Ref = p }
|
||||
|
@ -78,7 +76,7 @@ func (m *ProviderConfigReferencer) GetProviderConfigReference() *xpv1.Reference
|
|||
|
||||
// RequiredProviderConfigReferencer is a mock that implements the
|
||||
// RequiredProviderConfigReferencer interface.
|
||||
type RequiredProviderConfigReferencer struct{ Ref xpv1.Reference }
|
||||
type RequiredProviderConfigReferencer struct{ Ref xpv1.Reference } //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
|
||||
// SetProviderConfigReference sets the ProviderConfigReference.
|
||||
func (m *RequiredProviderConfigReferencer) SetProviderConfigReference(p xpv1.Reference) {
|
||||
|
@ -120,7 +118,7 @@ func (m *LocalConnectionSecretWriterTo) GetWriteConnectionSecretToReference() *x
|
|||
}
|
||||
|
||||
// ConnectionSecretWriterTo is a mock that implements ConnectionSecretWriterTo interface.
|
||||
type ConnectionSecretWriterTo struct{ Ref *xpv1.SecretReference }
|
||||
type ConnectionSecretWriterTo struct{ Ref *xpv1.SecretReference } //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
|
||||
// SetWriteConnectionSecretToReference sets the WriteConnectionSecretToReference.
|
||||
func (m *ConnectionSecretWriterTo) SetWriteConnectionSecretToReference(r *xpv1.SecretReference) {
|
||||
|
@ -175,7 +173,7 @@ func (m *CompositionReferencer) SetCompositionReference(r *corev1.ObjectReferenc
|
|||
func (m *CompositionReferencer) GetCompositionReference() *corev1.ObjectReference { return m.Ref }
|
||||
|
||||
// CompositionSelector is a mock that implements CompositionSelector interface.
|
||||
type CompositionSelector struct{ Sel *metav1.LabelSelector }
|
||||
type CompositionSelector struct{ Sel *metav1.LabelSelector } //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
|
||||
// SetCompositionSelector sets the CompositionSelector.
|
||||
func (m *CompositionSelector) SetCompositionSelector(s *metav1.LabelSelector) { m.Sel = s }
|
||||
|
@ -184,15 +182,15 @@ func (m *CompositionSelector) SetCompositionSelector(s *metav1.LabelSelector) {
|
|||
func (m *CompositionSelector) GetCompositionSelector() *metav1.LabelSelector { return m.Sel }
|
||||
|
||||
// CompositionRevisionReferencer is a mock that implements CompositionRevisionReferencer interface.
|
||||
type CompositionRevisionReferencer struct{ Ref *corev1.LocalObjectReference }
|
||||
type CompositionRevisionReferencer struct{ Ref *corev1.ObjectReference }
|
||||
|
||||
// SetCompositionRevisionReference sets the CompositionRevisionReference.
|
||||
func (m *CompositionRevisionReferencer) SetCompositionRevisionReference(r *corev1.LocalObjectReference) {
|
||||
func (m *CompositionRevisionReferencer) SetCompositionRevisionReference(r *corev1.ObjectReference) {
|
||||
m.Ref = r
|
||||
}
|
||||
|
||||
// GetCompositionRevisionReference gets the CompositionRevisionReference.
|
||||
func (m *CompositionRevisionReferencer) GetCompositionRevisionReference() *corev1.LocalObjectReference {
|
||||
func (m *CompositionRevisionReferencer) GetCompositionRevisionReference() *corev1.ObjectReference {
|
||||
return m.Ref
|
||||
}
|
||||
|
||||
|
@ -236,13 +234,13 @@ func (m *CompositeResourceDeleter) GetCompositeDeletePolicy() *xpv1.CompositeDel
|
|||
}
|
||||
|
||||
// CompositeResourceReferencer is a mock that implements CompositeResourceReferencer interface.
|
||||
type CompositeResourceReferencer struct{ Ref *reference.Composite }
|
||||
type CompositeResourceReferencer struct{ Ref *corev1.ObjectReference }
|
||||
|
||||
// SetResourceReference sets the composite resource reference.
|
||||
func (m *CompositeResourceReferencer) SetResourceReference(p *reference.Composite) { m.Ref = p }
|
||||
func (m *CompositeResourceReferencer) SetResourceReference(p *corev1.ObjectReference) { m.Ref = p }
|
||||
|
||||
// GetResourceReference gets the composite resource reference.
|
||||
func (m *CompositeResourceReferencer) GetResourceReference() *reference.Composite { return m.Ref }
|
||||
func (m *CompositeResourceReferencer) GetResourceReference() *corev1.ObjectReference { return m.Ref }
|
||||
|
||||
// ComposedResourcesReferencer is a mock that implements ComposedResourcesReferencer interface.
|
||||
type ComposedResourcesReferencer struct{ Refs []corev1.ObjectReference }
|
||||
|
@ -289,7 +287,7 @@ func (c *ConnectionDetailsLastPublishedTimer) GetConnectionDetailsLastPublishedT
|
|||
|
||||
// UserCounter is a mock that satisfies UserCounter
|
||||
// interface.
|
||||
type UserCounter struct{ Users int64 }
|
||||
type UserCounter struct{ Users int64 } //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
|
||||
// SetUsers sets the count of users.
|
||||
func (m *UserCounter) SetUsers(i int64) {
|
||||
|
@ -312,7 +310,7 @@ func (o *Object) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (o *Object) DeepCopyObject() runtime.Object {
|
||||
out := &Object{}
|
||||
j, err := json.Marshal(o)
|
||||
|
@ -339,7 +337,7 @@ func (m *Managed) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (m *Managed) DeepCopyObject() runtime.Object {
|
||||
out := &Managed{}
|
||||
j, err := json.Marshal(m)
|
||||
|
@ -364,7 +362,7 @@ type Composite struct {
|
|||
ConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
|
||||
xpv1.ResourceStatus
|
||||
xpv1.ConditionedStatus
|
||||
ConnectionDetailsLastPublishedTimer
|
||||
}
|
||||
|
||||
|
@ -373,7 +371,7 @@ func (m *Composite) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (m *Composite) DeepCopyObject() runtime.Object {
|
||||
out := &Composite{}
|
||||
j, err := json.Marshal(m)
|
||||
|
@ -389,7 +387,7 @@ type Composed struct {
|
|||
metav1.ObjectMeta
|
||||
ConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
xpv1.ResourceStatus
|
||||
xpv1.ConditionedStatus
|
||||
}
|
||||
|
||||
// GetObjectKind returns schema.ObjectKind.
|
||||
|
@ -397,7 +395,7 @@ func (m *Composed) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (m *Composed) DeepCopyObject() runtime.Object {
|
||||
out := &Composed{}
|
||||
j, err := json.Marshal(m)
|
||||
|
@ -421,7 +419,7 @@ type CompositeClaim struct {
|
|||
LocalConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
|
||||
xpv1.ResourceStatus
|
||||
xpv1.ConditionedStatus
|
||||
ConnectionDetailsLastPublishedTimer
|
||||
}
|
||||
|
||||
|
@ -430,7 +428,7 @@ func (m *CompositeClaim) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (m *CompositeClaim) DeepCopyObject() runtime.Object {
|
||||
out := &CompositeClaim{}
|
||||
j, err := json.Marshal(m)
|
||||
|
@ -479,7 +477,7 @@ func (m *Manager) GetRESTMapper() meta.RESTMapper { return m.RESTMapper }
|
|||
func (m *Manager) GetLogger() logr.Logger { return m.Logger }
|
||||
|
||||
// GV returns a mock schema.GroupVersion.
|
||||
var GV = schema.GroupVersion{Group: "g", Version: "v"} //nolint:gochecknoglobals // We treat this as a constant.
|
||||
var GV = schema.GroupVersion{Group: "g", Version: "v"}
|
||||
|
||||
// GVK returns the mock GVK of the given object.
|
||||
func GVK(o runtime.Object) schema.GroupVersionKind {
|
||||
|
@ -495,7 +493,7 @@ func SchemeWith(o ...runtime.Object) *runtime.Scheme {
|
|||
|
||||
// MockConnectionSecretOwner is a mock object that satisfies ConnectionSecretOwner
|
||||
// interface.
|
||||
type MockConnectionSecretOwner struct {
|
||||
type MockConnectionSecretOwner struct { //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
runtime.Object
|
||||
metav1.ObjectMeta
|
||||
|
||||
|
@ -528,7 +526,7 @@ func (m *MockConnectionSecretOwner) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (m *MockConnectionSecretOwner) DeepCopyObject() runtime.Object {
|
||||
out := &MockConnectionSecretOwner{}
|
||||
j, err := json.Marshal(m)
|
||||
|
@ -541,7 +539,7 @@ func (m *MockConnectionSecretOwner) DeepCopyObject() runtime.Object {
|
|||
|
||||
// MockLocalConnectionSecretOwner is a mock object that satisfies LocalConnectionSecretOwner
|
||||
// interface.
|
||||
type MockLocalConnectionSecretOwner struct {
|
||||
type MockLocalConnectionSecretOwner struct { //nolint:musttag // This is a fake implementation to be used in unit tests only.
|
||||
runtime.Object
|
||||
metav1.ObjectMeta
|
||||
|
||||
|
@ -559,7 +557,7 @@ func (m *MockLocalConnectionSecretOwner) SetWriteConnectionSecretToReference(r *
|
|||
m.Ref = r
|
||||
}
|
||||
|
||||
// SetPublishConnectionDetailsTo sets the publish connectionDetails to.
|
||||
// SetPublishConnectionDetailsTo sets the publish connectionDetails to
|
||||
func (m *MockLocalConnectionSecretOwner) SetPublishConnectionDetailsTo(r *xpv1.PublishConnectionDetailsTo) {
|
||||
m.To = r
|
||||
}
|
||||
|
@ -574,7 +572,7 @@ func (m *MockLocalConnectionSecretOwner) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (m *MockLocalConnectionSecretOwner) DeepCopyObject() runtime.Object {
|
||||
out := &MockLocalConnectionSecretOwner{}
|
||||
j, err := json.Marshal(m)
|
||||
|
@ -598,7 +596,7 @@ func (p *ProviderConfig) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (p *ProviderConfig) DeepCopyObject() runtime.Object {
|
||||
out := &ProviderConfig{}
|
||||
j, err := json.Marshal(p)
|
||||
|
@ -623,7 +621,7 @@ func (p *ProviderConfigUsage) GetObjectKind() schema.ObjectKind {
|
|||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object.
|
||||
// DeepCopyObject returns a copy of the object as runtime.Object
|
||||
func (p *ProviderConfigUsage) DeepCopyObject() runtime.Object {
|
||||
out := &ProviderConfigUsage{}
|
||||
j, err := json.Marshal(p)
|
||||
|
|
|
@ -25,20 +25,20 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/reference"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/claim"
|
||||
)
|
||||
|
||||
// A Conditioned may have conditions set or retrieved. Conditions are typically
|
||||
// indicate the status of both a resource and its reconciliation process.
|
||||
type Conditioned interface {
|
||||
SetConditions(c ...xpv1.Condition)
|
||||
GetCondition(ct xpv1.ConditionType) xpv1.Condition
|
||||
GetCondition(xpv1.ConditionType) xpv1.Condition
|
||||
}
|
||||
|
||||
// A ClaimReferencer may reference a resource claim.
|
||||
type ClaimReferencer interface {
|
||||
SetClaimReference(r *reference.Claim)
|
||||
GetClaimReference() *reference.Claim
|
||||
SetClaimReference(r *claim.Reference)
|
||||
GetClaimReference() *claim.Reference
|
||||
}
|
||||
|
||||
// A ManagedResourceReferencer may reference a concrete managed resource.
|
||||
|
@ -62,7 +62,7 @@ type ConnectionSecretWriterTo interface {
|
|||
}
|
||||
|
||||
// A ConnectionDetailsPublisherTo may write a connection details secret to a
|
||||
// secret store.
|
||||
// secret store
|
||||
type ConnectionDetailsPublisherTo interface {
|
||||
SetPublishConnectionDetailsTo(r *xpv1.PublishConnectionDetailsTo)
|
||||
GetPublishConnectionDetailsTo() *xpv1.PublishConnectionDetailsTo
|
||||
|
@ -107,21 +107,21 @@ type Finalizer interface {
|
|||
|
||||
// A CompositionSelector may select a composition of resources.
|
||||
type CompositionSelector interface {
|
||||
SetCompositionSelector(s *metav1.LabelSelector)
|
||||
SetCompositionSelector(*metav1.LabelSelector)
|
||||
GetCompositionSelector() *metav1.LabelSelector
|
||||
}
|
||||
|
||||
// A CompositionReferencer may reference a composition of resources.
|
||||
type CompositionReferencer interface {
|
||||
SetCompositionReference(ref *corev1.ObjectReference)
|
||||
SetCompositionReference(*corev1.ObjectReference)
|
||||
GetCompositionReference() *corev1.ObjectReference
|
||||
}
|
||||
|
||||
// A CompositionRevisionReferencer may reference a specific revision of a
|
||||
// composition of resources.
|
||||
type CompositionRevisionReferencer interface {
|
||||
SetCompositionRevisionReference(ref *corev1.LocalObjectReference)
|
||||
GetCompositionRevisionReference() *corev1.LocalObjectReference
|
||||
SetCompositionRevisionReference(*corev1.ObjectReference)
|
||||
GetCompositionRevisionReference() *corev1.ObjectReference
|
||||
}
|
||||
|
||||
// A CompositionRevisionSelector may reference a set of
|
||||
|
@ -134,7 +134,7 @@ type CompositionRevisionSelector interface {
|
|||
// A CompositionUpdater uses a composition, and may update which revision of
|
||||
// that composition it uses.
|
||||
type CompositionUpdater interface {
|
||||
SetCompositionUpdatePolicy(p *xpv1.UpdatePolicy)
|
||||
SetCompositionUpdatePolicy(*xpv1.UpdatePolicy)
|
||||
GetCompositionUpdatePolicy() *xpv1.UpdatePolicy
|
||||
}
|
||||
|
||||
|
@ -147,19 +147,19 @@ type CompositeResourceDeleter interface {
|
|||
|
||||
// A ComposedResourcesReferencer may reference the resources it composes.
|
||||
type ComposedResourcesReferencer interface {
|
||||
SetResourceReferences(refs []corev1.ObjectReference)
|
||||
SetResourceReferences([]corev1.ObjectReference)
|
||||
GetResourceReferences() []corev1.ObjectReference
|
||||
}
|
||||
|
||||
// A CompositeResourceReferencer can reference a composite resource.
|
||||
type CompositeResourceReferencer interface {
|
||||
SetResourceReference(r *reference.Composite)
|
||||
GetResourceReference() *reference.Composite
|
||||
SetResourceReference(r *corev1.ObjectReference)
|
||||
GetResourceReference() *corev1.ObjectReference
|
||||
}
|
||||
|
||||
// An EnvironmentConfigReferencer references a list of EnvironmentConfigs.
|
||||
type EnvironmentConfigReferencer interface {
|
||||
SetEnvironmentConfigReferences(refs []corev1.ObjectReference)
|
||||
SetEnvironmentConfigReferences([]corev1.ObjectReference)
|
||||
GetEnvironmentConfigReferences() []corev1.ObjectReference
|
||||
}
|
||||
|
||||
|
@ -176,12 +176,6 @@ type ConnectionDetailsPublishedTimer interface {
|
|||
GetConnectionDetailsLastPublishedTime() *metav1.Time
|
||||
}
|
||||
|
||||
// ReconciliationObserver can track data observed by resource reconciler.
|
||||
type ReconciliationObserver interface {
|
||||
SetObservedGeneration(generation int64)
|
||||
GetObservedGeneration() int64
|
||||
}
|
||||
|
||||
// An Object is a Kubernetes object.
|
||||
type Object interface {
|
||||
metav1.Object
|
||||
|
@ -190,7 +184,7 @@ type Object interface {
|
|||
|
||||
// A Managed is a Kubernetes object representing a concrete managed
|
||||
// resource (e.g. a CloudSQL instance).
|
||||
type Managed interface { //nolint:interfacebloat // This interface has to be big.
|
||||
type Managed interface {
|
||||
Object
|
||||
|
||||
ProviderConfigReferencer
|
||||
|
@ -234,8 +228,8 @@ type ProviderConfigUsageList interface {
|
|||
GetItems() []ProviderConfigUsage
|
||||
}
|
||||
|
||||
// A Composite resource (or XR) is composed of other resources.
|
||||
type Composite interface { //nolint:interfacebloat // This interface has to be big.
|
||||
// A Composite resource composes one or more Composed resources.
|
||||
type Composite interface {
|
||||
Object
|
||||
|
||||
CompositionSelector
|
||||
|
@ -244,16 +238,12 @@ type Composite interface { //nolint:interfacebloat // This interface has to be b
|
|||
CompositionRevisionReferencer
|
||||
CompositionRevisionSelector
|
||||
ComposedResourcesReferencer
|
||||
|
||||
Conditioned
|
||||
ReconciliationObserver
|
||||
}
|
||||
|
||||
// A LegacyComposite is a Crossplane v1 style legacy XR.
|
||||
type LegacyComposite interface {
|
||||
Composite
|
||||
EnvironmentConfigReferencer
|
||||
ClaimReferencer
|
||||
ConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
|
||||
Conditioned
|
||||
ConnectionDetailsPublishedTimer
|
||||
}
|
||||
|
||||
|
@ -263,11 +253,11 @@ type Composed interface {
|
|||
|
||||
Conditioned
|
||||
ConnectionSecretWriterTo
|
||||
ReconciliationObserver
|
||||
ConnectionDetailsPublisherTo
|
||||
}
|
||||
|
||||
// A CompositeClaim of a composite resource (XR).
|
||||
type CompositeClaim interface { //nolint:interfacebloat // This interface has to be big.
|
||||
// A CompositeClaim for a Composite resource.
|
||||
type CompositeClaim interface {
|
||||
Object
|
||||
|
||||
CompositionSelector
|
||||
|
@ -278,11 +268,8 @@ type CompositeClaim interface { //nolint:interfacebloat // This interface has to
|
|||
CompositeResourceDeleter
|
||||
CompositeResourceReferencer
|
||||
LocalConnectionSecretWriterTo
|
||||
ConnectionDetailsPublisherTo
|
||||
|
||||
Conditioned
|
||||
ConnectionDetailsPublishedTimer
|
||||
ReconciliationObserver
|
||||
}
|
||||
|
||||
// A Claim of a composite resource (XR).
|
||||
type Claim = CompositeClaim
|
||||
|
|
|
@ -16,12 +16,7 @@ limitations under the License.
|
|||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/claim"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composed"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composite"
|
||||
)
|
||||
import "github.com/crossplane/crossplane-runtime/pkg/resource/fake"
|
||||
|
||||
// We test that our fakes satisfy our interfaces here rather than in the fake
|
||||
// package to avoid a cyclic dependency.
|
||||
|
@ -34,8 +29,4 @@ var (
|
|||
_ CompositeClaim = &fake.CompositeClaim{}
|
||||
_ Composite = &fake.Composite{}
|
||||
_ Composed = &fake.Composed{}
|
||||
|
||||
_ CompositeClaim = &claim.Unstructured{}
|
||||
_ Composite = &composite.Unstructured{}
|
||||
_ Composed = &composed.Unstructured{}
|
||||
)
|
||||
|
|
|
@ -47,7 +47,7 @@ func NewPredicates(fn PredicateFn) predicate.Funcs {
|
|||
// To be more specific, it accepts update events that have changes in one of the followings:
|
||||
// - `metadata.annotations` (except for certain annotations)
|
||||
// - `metadata.labels`
|
||||
// - `spec`.
|
||||
// - `spec`
|
||||
func DesiredStateChanged() predicate.Predicate {
|
||||
return predicate.Or(
|
||||
AnnotationChangedPredicate{
|
||||
|
|
|
@ -42,14 +42,14 @@ const (
|
|||
errApplyPCU = "cannot apply ProviderConfigUsage"
|
||||
)
|
||||
|
||||
type missingRefError struct{ error }
|
||||
type errMissingRef struct{ error }
|
||||
|
||||
func (m missingRefError) MissingReference() bool { return true }
|
||||
func (m errMissingRef) MissingReference() bool { return true }
|
||||
|
||||
// IsMissingReference returns true if an error indicates that a managed
|
||||
// resource is missing a required reference..
|
||||
func IsMissingReference(err error) bool {
|
||||
_, ok := err.(interface {
|
||||
_, ok := err.(interface { //nolint: errorlint // Skip errorlint for interface type
|
||||
MissingReference() bool
|
||||
})
|
||||
return ok
|
||||
|
@ -138,12 +138,11 @@ func NewProviderConfigUsageTracker(c client.Client, of ProviderConfigUsage) *Pro
|
|||
// managed resource's usage is updated if the managed resource is updated to
|
||||
// reference a misconfigured ProviderConfig.
|
||||
func (u *ProviderConfigUsageTracker) Track(ctx context.Context, mg Managed) error {
|
||||
//nolint:forcetypeassert // Will always be a PCU.
|
||||
pcu := u.of.DeepCopyObject().(ProviderConfigUsage)
|
||||
gvk := mg.GetObjectKind().GroupVersionKind()
|
||||
ref := mg.GetProviderConfigReference()
|
||||
if ref == nil {
|
||||
return missingRefError{errors.New(errMissingPCRef)}
|
||||
return errMissingRef{errors.New(errMissingPCRef)}
|
||||
}
|
||||
|
||||
pcu.SetName(string(mg.GetUID()))
|
||||
|
@ -159,7 +158,6 @@ func (u *ProviderConfigUsageTracker) Track(ctx context.Context, mg Managed) erro
|
|||
err := u.c.Apply(ctx, pcu,
|
||||
MustBeControllableBy(mg.GetUID()),
|
||||
AllowUpdateIf(func(current, _ runtime.Object) bool {
|
||||
//nolint:forcetypeassert // Will always be a PCU.
|
||||
return current.(ProviderConfigUsage).GetProviderConfigReference() != pcu.GetProviderConfigReference()
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -261,12 +261,12 @@ func TestTrack(t *testing.T) {
|
|||
args: args{
|
||||
mg: &fake.Managed{},
|
||||
},
|
||||
want: missingRefError{errors.New(errMissingPCRef)},
|
||||
want: errMissingRef{errors.New(errMissingPCRef)},
|
||||
},
|
||||
"NopUpdate": {
|
||||
reason: "No error should be returned if the apply fails because it would be a no-op",
|
||||
fields: fields{
|
||||
c: ApplyFn(func(ctx context.Context, _ client.Object, ao ...ApplyOption) error {
|
||||
c: ApplyFn(func(c context.Context, r client.Object, ao ...ApplyOption) error {
|
||||
for _, fn := range ao {
|
||||
// Exercise the MustBeControllableBy and AllowUpdateIf
|
||||
// ApplyOptions. The former should pass because the
|
||||
|
@ -279,7 +279,7 @@ func TestTrack(t *testing.T) {
|
|||
Ref: xpv1.Reference{Name: name},
|
||||
},
|
||||
}
|
||||
if err := fn(ctx, current, nil); err != nil {
|
||||
if err := fn(context.TODO(), current, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ func TestTrack(t *testing.T) {
|
|||
"ApplyError": {
|
||||
reason: "Errors applying the ProviderConfigUsage should be returned",
|
||||
fields: fields{
|
||||
c: ApplyFn(func(_ context.Context, _ client.Object, _ ...ApplyOption) error {
|
||||
c: ApplyFn(func(c context.Context, r client.Object, ao ...ApplyOption) error {
|
||||
return errBoom
|
||||
}),
|
||||
of: &fake.ProviderConfigUsage{},
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// ReferenceStatusType is an enum type for the possible values for a Reference Status.
|
||||
// ReferenceStatusType is an enum type for the possible values for a Reference Status
|
||||
type ReferenceStatusType int
|
||||
|
||||
// Reference statuses.
|
||||
|
@ -39,7 +39,7 @@ func (t ReferenceStatusType) String() string {
|
|||
return []string{"Unknown", "NotFound", "NotReady", "Ready"}[t]
|
||||
}
|
||||
|
||||
// ReferenceStatus has the name and status of a reference.
|
||||
// ReferenceStatus has the name and status of a reference
|
||||
type ReferenceStatus struct {
|
||||
Name string
|
||||
Status ReferenceStatusType
|
||||
|
@ -55,8 +55,8 @@ func (r ReferenceStatus) String() string {
|
|||
type CanReference runtime.Object
|
||||
|
||||
// An AttributeReferencer resolves cross-resource attribute references. See
|
||||
// https://github.com/crossplane/crossplane/blob/main/design/one-pager-cross-resource-referencing.md
|
||||
// for more information.
|
||||
// https://github.com/crossplane/crossplane/blob/master/design/one-pager-cross-resource-referencing.md
|
||||
// for more information
|
||||
type AttributeReferencer interface {
|
||||
// GetStatus retries the referenced resource, as well as other non-managed
|
||||
// resources (like a `Provider`) and reports their readiness for use as a
|
||||
|
|
|
@ -22,15 +22,12 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kunstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
@ -38,7 +35,6 @@ import (
|
|||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/resource/unstructured"
|
||||
)
|
||||
|
||||
// SecretTypeConnection is the type of Crossplane connection secrets.
|
||||
|
@ -50,10 +46,6 @@ const (
|
|||
ExternalResourceTagKeyKind = "crossplane-kind"
|
||||
ExternalResourceTagKeyName = "crossplane-name"
|
||||
ExternalResourceTagKeyProvider = "crossplane-providerconfig"
|
||||
|
||||
errMarshalJSON = "cannot marshal to JSON"
|
||||
errUnmarshalJSON = "cannot unmarshal JSON data"
|
||||
errStructFromUnstructured = "cannot create Struct"
|
||||
)
|
||||
|
||||
// A ManagedKind contains the type metadata for a kind of managed resource.
|
||||
|
@ -191,35 +183,35 @@ func IgnoreNotFound(err error) error {
|
|||
|
||||
// IsAPIError returns true if the given error's type is of Kubernetes API error.
|
||||
func IsAPIError(err error) bool {
|
||||
_, ok := err.(kerrors.APIStatus)
|
||||
_, ok := err.(kerrors.APIStatus) //nolint: errorlint // we assert against the kerrors.APIStatus Interface which does not implement the error interface
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsAPIErrorWrapped returns true if err is a K8s API error, or recursively wraps a K8s API error.
|
||||
// IsAPIErrorWrapped returns true if err is a K8s API error, or recursively wraps a K8s API error
|
||||
func IsAPIErrorWrapped(err error) bool {
|
||||
return IsAPIError(errors.Cause(err))
|
||||
}
|
||||
|
||||
// IsConditionTrue returns if condition status is true.
|
||||
// IsConditionTrue returns if condition status is true
|
||||
func IsConditionTrue(c xpv1.Condition) bool {
|
||||
return c.Status == corev1.ConditionTrue
|
||||
}
|
||||
|
||||
// An Applicator applies changes to an object.
|
||||
type Applicator interface {
|
||||
Apply(ctx context.Context, obj client.Object, o ...ApplyOption) error
|
||||
Apply(context.Context, client.Object, ...ApplyOption) error
|
||||
}
|
||||
|
||||
type shouldRetryFunc func(error) bool
|
||||
|
||||
// An ApplicatorWithRetry applies changes to an object, retrying on transient failures.
|
||||
// An ApplicatorWithRetry applies changes to an object, retrying on transient failures
|
||||
type ApplicatorWithRetry struct {
|
||||
Applicator
|
||||
shouldRetry shouldRetryFunc
|
||||
backoff wait.Backoff
|
||||
}
|
||||
|
||||
// Apply invokes nested Applicator's Apply retrying on designated errors.
|
||||
// Apply invokes nested Applicator's Apply retrying on designated errors
|
||||
func (awr *ApplicatorWithRetry) Apply(ctx context.Context, c client.Object, opts ...ApplyOption) error {
|
||||
return retry.OnError(awr.backoff, awr.shouldRetry, func() error {
|
||||
return awr.Applicator.Apply(ctx, c, opts...)
|
||||
|
@ -272,9 +264,9 @@ func UpdateFn(fn func(current, desired runtime.Object)) ApplyOption {
|
|||
}
|
||||
}
|
||||
|
||||
type notControllableError struct{ error }
|
||||
type errNotControllable struct{ error }
|
||||
|
||||
func (e notControllableError) NotControllable() bool {
|
||||
func (e errNotControllable) NotControllable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -282,7 +274,7 @@ func (e notControllableError) NotControllable() bool {
|
|||
// resource is not controllable - i.e. that it another resource is not and may
|
||||
// not become its controller reference.
|
||||
func IsNotControllable(err error) bool {
|
||||
_, ok := err.(interface {
|
||||
_, ok := err.(interface { //nolint: errorlint // Skip errorlint for interface type
|
||||
NotControllable() bool
|
||||
})
|
||||
return ok
|
||||
|
@ -295,17 +287,14 @@ func IsNotControllable(err error) bool {
|
|||
// cannot be controlled by the supplied UID.
|
||||
func MustBeControllableBy(u types.UID) ApplyOption {
|
||||
return func(_ context.Context, current, _ runtime.Object) error {
|
||||
mo, ok := current.(metav1.Object)
|
||||
if !ok {
|
||||
return notControllableError{errors.Errorf("existing object is missing object metadata")}
|
||||
}
|
||||
c := metav1.GetControllerOf(mo)
|
||||
c := metav1.GetControllerOf(current.(metav1.Object))
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.UID != u {
|
||||
return notControllableError{errors.Errorf("existing object is not controlled by UID %q", u)}
|
||||
return errNotControllable{errors.Errorf("existing object is not controlled by UID %q", u)}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -325,40 +314,37 @@ func MustBeControllableBy(u types.UID) ApplyOption {
|
|||
// secret or cannot be controlled by the supplied UID.
|
||||
func ConnectionSecretMustBeControllableBy(u types.UID) ApplyOption {
|
||||
return func(_ context.Context, current, _ runtime.Object) error {
|
||||
s, ok := current.(*corev1.Secret)
|
||||
if !ok {
|
||||
return errors.New("current resource is not a Secret")
|
||||
}
|
||||
s := current.(*corev1.Secret)
|
||||
c := metav1.GetControllerOf(s)
|
||||
|
||||
switch {
|
||||
case c == nil && s.Type != SecretTypeConnection:
|
||||
return notControllableError{errors.Errorf("refusing to modify uncontrolled secret of type %q", s.Type)}
|
||||
return errNotControllable{errors.Errorf("refusing to modify uncontrolled secret of type %q", s.Type)}
|
||||
case c == nil:
|
||||
return nil
|
||||
case c.UID != u:
|
||||
return notControllableError{errors.Errorf("existing secret is not controlled by UID %q", u)}
|
||||
return errNotControllable{errors.Errorf("existing secret is not controlled by UID %q", u)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type notAllowedError struct{ error }
|
||||
type errNotAllowed struct{ error }
|
||||
|
||||
func (e notAllowedError) NotAllowed() bool {
|
||||
func (e errNotAllowed) NotAllowed() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// NewNotAllowed returns a new NotAllowed error.
|
||||
// NewNotAllowed returns a new NotAllowed error
|
||||
func NewNotAllowed(message string) error {
|
||||
return notAllowedError{error: errors.New(message)}
|
||||
return errNotAllowed{error: errors.New(message)}
|
||||
}
|
||||
|
||||
// IsNotAllowed returns true if the supplied error indicates that an operation
|
||||
// was not allowed.
|
||||
func IsNotAllowed(err error) bool {
|
||||
_, ok := err.(interface {
|
||||
_, ok := err.(interface { //nolint: errorlint // Skip errorlint for interface type
|
||||
NotAllowed() bool
|
||||
})
|
||||
return ok
|
||||
|
@ -373,7 +359,7 @@ func AllowUpdateIf(fn func(current, desired runtime.Object) bool) ApplyOption {
|
|||
if fn(current, desired) {
|
||||
return nil
|
||||
}
|
||||
return notAllowedError{errors.New("update not allowed")}
|
||||
return errNotAllowed{errors.New("update not allowed")}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,12 +367,8 @@ func AllowUpdateIf(fn func(current, desired runtime.Object) bool) ApplyOption {
|
|||
// supplied string pointer. This is useful to detect whether the Apply call
|
||||
// was a no-op.
|
||||
func StoreCurrentRV(origRV *string) ApplyOption {
|
||||
return func(_ context.Context, current, _ runtime.Object) error {
|
||||
mo, ok := current.(metav1.Object)
|
||||
if !ok {
|
||||
return errors.New("current resource is missing object metadata")
|
||||
}
|
||||
*origRV = mo.GetResourceVersion()
|
||||
return func(_ context.Context, current, desired runtime.Object) error {
|
||||
*origRV = current.(client.Object).GetResourceVersion()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -433,30 +415,3 @@ func StableNAndSomeMore(n int, names []string) string {
|
|||
sort.Strings(cpy)
|
||||
return FirstNAndSomeMore(n, cpy)
|
||||
}
|
||||
|
||||
// AsProtobufStruct converts the given object to a structpb.Struct for usage with gRPC
|
||||
// connections.
|
||||
// Copied from:
|
||||
// https://github.com/crossplane/crossplane/blob/release-1.16/internal/controller/apiextensions/composite/composition_functions.go#L761
|
||||
func AsProtobufStruct(o runtime.Object) (*structpb.Struct, error) {
|
||||
// If the supplied object is *Unstructured we don't need to round-trip.
|
||||
if u, ok := o.(*kunstructured.Unstructured); ok {
|
||||
s, err := structpb.NewStruct(u.Object)
|
||||
return s, errors.Wrap(err, errStructFromUnstructured)
|
||||
}
|
||||
|
||||
// If the supplied object wraps *Unstructured we don't need to round-trip.
|
||||
if w, ok := o.(unstructured.Wrapper); ok {
|
||||
s, err := structpb.NewStruct(w.GetUnstructured().Object)
|
||||
return s, errors.Wrap(err, errStructFromUnstructured)
|
||||
}
|
||||
|
||||
// Fall back to a JSON round-trip.
|
||||
b, err := json.Marshal(o)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMarshalJSON)
|
||||
}
|
||||
|
||||
s := &structpb.Struct{}
|
||||
return s, errors.Wrap(s.UnmarshalJSON(b), errUnmarshalJSON)
|
||||
}
|
||||
|
|
|
@ -249,7 +249,6 @@ func TestGetKind(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMustCreateObject(t *testing.T) {
|
||||
type args struct {
|
||||
kind schema.GroupVersionKind
|
||||
|
@ -291,14 +290,14 @@ func TestIgnore(t *testing.T) {
|
|||
}{
|
||||
"IgnoreError": {
|
||||
args: args{
|
||||
is: func(_ error) bool { return true },
|
||||
is: func(err error) bool { return true },
|
||||
err: errBoom,
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
"PropagateError": {
|
||||
args: args{
|
||||
is: func(_ error) bool { return false },
|
||||
is: func(err error) bool { return false },
|
||||
err: errBoom,
|
||||
},
|
||||
want: errBoom,
|
||||
|
@ -328,7 +327,7 @@ func TestIgnoreAny(t *testing.T) {
|
|||
}{
|
||||
"IgnoreError": {
|
||||
args: args{
|
||||
is: []ErrorIs{func(_ error) bool { return true }},
|
||||
is: []ErrorIs{func(err error) bool { return true }},
|
||||
err: errBoom,
|
||||
},
|
||||
want: nil,
|
||||
|
@ -336,8 +335,8 @@ func TestIgnoreAny(t *testing.T) {
|
|||
"IgnoreErrorArr": {
|
||||
args: args{
|
||||
is: []ErrorIs{
|
||||
func(_ error) bool { return true },
|
||||
func(_ error) bool { return false },
|
||||
func(err error) bool { return true },
|
||||
func(err error) bool { return false },
|
||||
},
|
||||
err: errBoom,
|
||||
},
|
||||
|
@ -345,7 +344,7 @@ func TestIgnoreAny(t *testing.T) {
|
|||
},
|
||||
"PropagateError": {
|
||||
args: args{
|
||||
is: []ErrorIs{func(_ error) bool { return false }},
|
||||
is: []ErrorIs{func(err error) bool { return false }},
|
||||
err: errBoom,
|
||||
},
|
||||
want: errBoom,
|
||||
|
@ -422,7 +421,7 @@ func TestIsNotControllable(t *testing.T) {
|
|||
},
|
||||
"NotControllableError": {
|
||||
reason: "An that has a 'NotControllable() bool' method indicates something is not controllable.",
|
||||
err: notControllableError{errors.New("boom")},
|
||||
err: errNotControllable{errors.New("boom")},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
@ -435,6 +434,7 @@ func TestIsNotControllable(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMustBeControllableBy(t *testing.T) {
|
||||
|
@ -479,7 +479,7 @@ func TestMustBeControllableBy(t *testing.T) {
|
|||
Controller: &controller,
|
||||
}}}},
|
||||
},
|
||||
want: notControllableError{errors.Errorf("existing object is not controlled by UID %q", uid)},
|
||||
want: errNotControllable{errors.Errorf("existing object is not controlled by UID %q", uid)},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -543,7 +543,7 @@ func TestConnectionSecretMustBeControllableBy(t *testing.T) {
|
|||
Type: SecretTypeConnection,
|
||||
},
|
||||
},
|
||||
want: notControllableError{errors.Errorf("existing secret is not controlled by UID %q", uid)},
|
||||
want: errNotControllable{errors.Errorf("existing secret is not controlled by UID %q", uid)},
|
||||
},
|
||||
"UncontrolledOpaqueSecret": {
|
||||
reason: "A Secret of corev1.SecretTypeOpqaue with no controller is not controllable",
|
||||
|
@ -551,7 +551,7 @@ func TestConnectionSecretMustBeControllableBy(t *testing.T) {
|
|||
args: args{
|
||||
current: &corev1.Secret{Type: corev1.SecretTypeOpaque},
|
||||
},
|
||||
want: notControllableError{errors.Errorf("refusing to modify uncontrolled secret of type %q", corev1.SecretTypeOpaque)},
|
||||
want: errNotControllable{errors.Errorf("refusing to modify uncontrolled secret of type %q", corev1.SecretTypeOpaque)},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -582,18 +582,18 @@ func TestAllowUpdateIf(t *testing.T) {
|
|||
}{
|
||||
"Allowed": {
|
||||
reason: "No error should be returned when the supplied function returns true",
|
||||
fn: func(_, _ runtime.Object) bool { return true },
|
||||
fn: func(current, desired runtime.Object) bool { return true },
|
||||
args: args{
|
||||
current: &object{},
|
||||
},
|
||||
},
|
||||
"NotAllowed": {
|
||||
reason: "An error that satisfies IsNotAllowed should be returned when the supplied function returns false",
|
||||
fn: func(_, _ runtime.Object) bool { return false },
|
||||
fn: func(current, desired runtime.Object) bool { return false },
|
||||
args: args{
|
||||
current: &object{},
|
||||
},
|
||||
want: notAllowedError{errors.New("update not allowed")},
|
||||
want: errNotAllowed{errors.New("update not allowed")},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -616,10 +616,9 @@ func TestGetExternalTags(t *testing.T) {
|
|||
want map[string]string
|
||||
}{
|
||||
"SuccessfulWithProviderConfig": {
|
||||
o: &fake.Managed{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
o: &fake.Managed{ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
ProviderConfigReferencer: fake.ProviderConfigReferencer{Ref: &xpv1.Reference{Name: provName}},
|
||||
},
|
||||
want: map[string]string{
|
||||
|
@ -640,9 +639,9 @@ func TestGetExternalTags(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// single test case => not using tables.
|
||||
func Test_notControllableError_NotControllable(t *testing.T) {
|
||||
err := notControllableError{
|
||||
// single test case => not using tables
|
||||
func Test_errNotControllable_NotControllable(t *testing.T) {
|
||||
err := errNotControllable{
|
||||
errors.New("test-error"),
|
||||
}
|
||||
|
||||
|
@ -651,9 +650,9 @@ func Test_notControllableError_NotControllable(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// single test case => not using tables.
|
||||
func Test_notAllowedError_NotAllowed(t *testing.T) {
|
||||
err := notAllowedError{
|
||||
// single test case => not using tables
|
||||
func Test_errNotAllowed_NotAllowed(t *testing.T) {
|
||||
err := errNotAllowed{
|
||||
errors.New("test-error"),
|
||||
}
|
||||
|
||||
|
@ -835,12 +834,11 @@ func TestUpdate(t *testing.T) {
|
|||
want runtime.Object
|
||||
}{
|
||||
"Update": {
|
||||
args: args{
|
||||
fn: func(current, desired runtime.Object) {
|
||||
c, d := current.(*corev1.Secret), desired.(*corev1.Secret)
|
||||
args: args{fn: func(current, desired runtime.Object) {
|
||||
c, d := current.(*corev1.Secret), desired.(*corev1.Secret)
|
||||
|
||||
c.StringData = d.StringData
|
||||
},
|
||||
c.StringData = d.StringData
|
||||
},
|
||||
current: &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "current",
|
||||
|
@ -895,7 +893,7 @@ func TestFirstNAndSomeMore(t *testing.T) {
|
|||
{args: args{n: 3, names: []string{"a"}}, want: "a"},
|
||||
{args: args{n: 3, names: []string{}}, want: ""},
|
||||
{args: args{n: 3, names: []string{"a", "c", "e", "b", "d"}}, want: "a, c, e, and 2 more"},
|
||||
{args: args{n: 3, names: []string{"a", "b", "b", "b", "d"}}, want: "a, b, b, and 2 more"}, //nolint:dupword // Intentional.
|
||||
{args: args{n: 3, names: []string{"a", "b", "b", "b", "d"}}, want: "a, b, b, and 2 more"},
|
||||
{args: args{n: 2, names: []string{"a", "c", "e", "b", "d"}}, want: "a, c, and 3 more"},
|
||||
{args: args{n: 0, names: []string{"a", "c", "e", "b", "d"}}, want: "5"},
|
||||
{args: args{n: -7, names: []string{"a", "c", "e", "b", "d"}}, want: "5"},
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue