From 107ffce1670bb00b8fe45990688524e79dc248ec Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Tue, 24 Oct 2023 08:14:57 +0200 Subject: [PATCH 01/23] Initial commit Signed-off-by: Maximilian Braun (SAP) --- .gitignore | 21 ++++++ LICENSE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 6 +- 3 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b735ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/README.md b/README.md index 4a270c6..88a649f 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -# xp-testing \ No newline at end of file +<<<<<<< HEAD +# xp-testing +======= +# xp-testiing +>>>>>>> 352ec62 (Initial commit) From 097eee2c38917f308866b281da06170bc4088fc3 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Tue, 24 Oct 2023 08:15:21 +0200 Subject: [PATCH 02/23] Update README.md Signed-off-by: Maximilian Braun (SAP) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 88a649f..975fcce 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ <<<<<<< HEAD +<<<<<<< HEAD # xp-testing ======= # xp-testiing >>>>>>> 352ec62 (Initial commit) +======= +# xp-testing +>>>>>>> 478ccae (Update README.md) From 78ebdd53e001f1b25b8ea8f63ea3f145764814ac Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 00:17:51 +0200 Subject: [PATCH 03/23] initial import Co-authored-by: Christian Volk Co-authored-by: Mirza Kopic Co-authored-by: Stephan Discher Co-authored-by: Johannes Ott Co-authored-by: Denis Holschuh Signed-off-by: Maximilian Braun --- .editorconfig | 16 + .github/workflows/codeql.yml | 42 ++ .github/workflows/lint.yaml | 49 ++ .gitignore | 3 + .golangci.yml | 200 ++++++++ DCO | 36 ++ go.mod | 98 ++++ go.sum | 825 ++++++++++++++++++++++++++++++++ internal/docker/docker.go | 45 ++ internal/docker/docker_test.go | 280 +++++++++++ internal/xpkg/xpkg.go | 56 +++ internal/xpkg/xpkg_test.go | 164 +++++++ pkg/conditions/conditions.go | 46 ++ pkg/envvar/envvar.go | 33 ++ pkg/envvar/envvar_test.go | 69 +++ pkg/images/lookup.go | 47 ++ pkg/images/lookup_test.go | 52 ++ pkg/logging/logging.go | 36 ++ pkg/logging/logging_test.go | 38 ++ pkg/resources/resources.go | 358 ++++++++++++++ pkg/setup/setup.go | 105 ++++ pkg/xenvfuncs/xenvfuncs.go | 534 +++++++++++++++++++++ pkg/xenvfuncs/xenvfuncs_test.go | 294 ++++++++++++ 23 files changed, 3426 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/lint.yaml create mode 100644 .golangci.yml create mode 100644 DCO create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/docker/docker.go create mode 100644 internal/docker/docker_test.go create mode 100644 internal/xpkg/xpkg.go create mode 100644 internal/xpkg/xpkg_test.go create mode 100644 pkg/conditions/conditions.go create mode 100644 pkg/envvar/envvar.go create mode 100644 pkg/envvar/envvar_test.go create mode 100644 pkg/images/lookup.go create mode 100644 pkg/images/lookup_test.go create mode 100644 pkg/logging/logging.go create mode 100644 pkg/logging/logging_test.go create mode 100644 pkg/resources/resources.go create mode 100644 pkg/setup/setup.go create mode 100644 pkg/xenvfuncs/xenvfuncs.go create mode 100644 pkg/xenvfuncs/xenvfuncs_test.go diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..288a6a1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..2e50bcf --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,42 @@ +name: CodeQL + +on: + push: + branches: + - main + - release-* + workflow_dispatch: {} + +jobs: + detect-noop: + runs-on: ubuntu-20.04 + outputs: + noop: ${{ steps.noop.outputs.should_skip }} + steps: + - name: Detect No-op Changes + id: noop + uses: fkirc/skip-duplicate-actions@v2.1.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + paths_ignore: '["**.md", "**.png", "**.jpg"]' + do_not_skip: '["workflow_dispatch", "schedule", "push"]' + concurrent_skipping: false + + analyze: + runs-on: ubuntu-20.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: go + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..4812426 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,49 @@ +--- +name: golangci-lint + +on: + push: + tags: + - v* + branches: + - main + pull_request: +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + # pull-requests: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v4 + with: + go-version: '1.20' + cache: false + - uses: actions/checkout@v3 + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version + # version: v1.29 + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + args: --timeout=10m # --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true + + # Optional: if set to true then the all caching functionality will be complete disabled, + # takes precedence over all other caching options. + # skip-cache: true + + # Optional: if set to true then the action don't cache or restore ~/go/pkg. + # skip-pkg-cache: true + + # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. + # skip-build-cache: true diff --git a/.gitignore b/.gitignore index 3b735ec..1de9dbd 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ # Go workspace file go.work + + +.idea diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..3c0aaca --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,200 @@ +run: + deadline: 2m + + skip-files: + - "zz_generated\\..+\\.go$" + +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" + format: colored-line-number + +linters-settings: + errcheck: + # report about not checking of errors in type assetions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false + + # [deprecated] comma-separated list of pairs of the form pkg:regex + # the regex is used to ignore names within pkg. (default "fmt:.*"). + # see https://github.com/kisielk/errcheck#the-deprecated-method for details + ignore: fmt:.*,io/ioutil:^Read.* + + govet: + # report about shadowed variables + check-shadowing: false + + golint: + # minimal confidence for issues, default is 0.8 + min-confidence: 0.8 + + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + + goimports: + # put imports beginning with prefix after 3rd-party packages; + # it's a comma-separated list of prefixes + local-prefixes: github.tools.sap/cloud-orchestration/managed-control-plane-operator + + gocyclo: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 10 + + maligned: + # print struct with more effective memory layout or not, false by default + suggest-new: true + + dupl: + # tokens count to trigger issue, 150 by default + threshold: 100 + + goconst: + # minimal length of string constant, 3 by default + min-len: 3 + # minimal occurrences count to trigger, 3 by default + min-occurrences: 5 + + lll: + # Max line length, lines longer will be reported. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option. + # Default: 120. + line-length: 120 + # Tab width in spaces. + # Default: 1 + tab-width: 1 + + unused: + # treat code as a program (not a library) and report unused exported identifiers; default is false. + # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find funcs usages. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + + unparam: + # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + + nakedret: + # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 + max-func-lines: 30 + + prealloc: + # XXX: we don't recommend using this linter before doing performance profiling. + # For most programs usage of prealloc will be a premature optimization. + + # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # True by default. + simple: true + range-loops: true # Report preallocation suggestions on range loops, true by default + for-loops: false # Report preallocation suggestions on for loops, false by default + + gocritic: + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks. + # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - performance + + settings: # settings passed to gocritic + captLocal: # must be valid enabled check name + paramsOnly: true + rangeValCopy: + sizeThreshold: 32 + +linters: + enable: + - megacheck + - govet + - gocyclo + - gocritic + - interfacer + - goconst + - goimports + - gofmt # We enable this as well as goimports for its simplify mode. + - prealloc + - golint + - unconvert + - misspell + - nakedret + + presets: + - bugs + - unused + fast: false + + +issues: + # Excluding configuration per-path and per-linter + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test(ing)?\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + - scopelint + - unparam + + # Ease some gocritic warnings on test files. + - path: _test\.go + text: "(unnamedResult|exitAfterDefer)" + linters: + - gocritic + + # These are performance optimisations rather than style issues per se. + # They warn when function arguments or range values copy a lot of memory + # rather than using a pointer. + - text: "(hugeParam|rangeValCopy):" + linters: + - gocritic + + # This "TestMain should call os.Exit to set exit code" warning is not clever + # enough to notice that we call a helper method that calls os.Exit. + - text: "SA3000:" + linters: + - staticcheck + + - text: "k8s.io/api/core/v1" + linters: + - goimports + + # This is a "potential hardcoded credentials" warning. It's triggered by + # any variable with 'secret' in the same, and thus hits a lot of false + # positives in Kubernetes land where a Secret is an object type. + - text: "G101:" + linters: + - gosec + - gas + + # This is an 'errors unhandled' warning that duplicates errcheck. + - text: "G104:" + linters: + - gosec + - gas + + # Independently from option `exclude` we use default exclude patterns, + # it can be disabled by this option. To list all + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. + exclude-use-default: false + + # Show only new issues: if there are unstaged changes or untracked files, + # only those changes are analyzed, else only changes in HEAD~ are analyzed. + # It's a super-useful option for integration of golangci-lint into existing + # large codebase. It's not practical to fix all existing issues at the moment + # of integration: much better don't allow issues in new code. + # Default is false. + new: false + + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-per-linter: 0 + + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 0 \ No newline at end of file diff --git a/DCO b/DCO new file mode 100644 index 0000000..716561d --- /dev/null +++ b/DCO @@ -0,0 +1,36 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..452aa48 --- /dev/null +++ b/go.mod @@ -0,0 +1,98 @@ +module github.com/maximilianbraun/xp-testing + +go 1.20 + +require ( + github.com/GoogleContainerTools/container-diff v0.17.0 + github.com/crossplane/crossplane v0.0.0-00010101000000-000000000000 + github.com/crossplane/crossplane-runtime v0.19.2 + github.com/pkg/errors v0.9.1 + github.com/samber/lo v1.38.1 + github.com/stretchr/testify v1.8.4 + github.com/vladimirvivien/gexe v0.2.0 + k8s.io/api v0.27.4 + k8s.io/apiextensions-apiserver v0.27.4 + k8s.io/apimachinery v0.27.4 + k8s.io/client-go v0.27.4 + k8s.io/klog/v2 v2.100.1 + sigs.k8s.io/controller-runtime v0.15.0 + sigs.k8s.io/e2e-framework v0.2.0 + sigs.k8s.io/kind v0.20.0 +) + +require ( + github.com/BurntSushi/toml v1.2.1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect + github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/cli v24.0.4+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v24.0.4+incompatible // indirect + github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/go-logr/logr v1.2.4 // 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.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/gnostic v0.6.9 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-containerregistry v0.16.1 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.11.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 // 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.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace github.com/crossplane/crossplane => github.com/crossplane/crossplane v1.11.3 + +replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.19.2 + +replace github.com/docker/docker => github.com/docker/docker v1.4.2-0.20190219180918-740349757396 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..19d53fa --- /dev/null +++ b/go.sum @@ -0,0 +1,825 @@ +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= +code.cloudfoundry.org/bytefmt v0.0.0-20180906201452-2aa6f33b730c/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleContainerTools/container-diff v0.17.0 h1:P9va/peQsiBcFuL+hcZWHp3Ry7bCLLoNhUrjj7DBNFQ= +github.com/GoogleContainerTools/container-diff v0.17.0/go.mod h1:pddOdZb5Wghtb2fmqbKy7Kj/sgoafW9AvUp4KS9svmg= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +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/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +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/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M= +github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/crossplane/crossplane v1.11.3 h1:nvV8ivMZd98zSr7SLsu4IFNbQg4c+YvdgxwvbtxSnL8= +github.com/crossplane/crossplane v1.11.3/go.mod h1:EV76e/7nJ8tJ+wrpx+2nKNMEic92iI13n4RwfI4Pgy0= +github.com/crossplane/crossplane-runtime v0.19.2 h1:9qBnhpqKN4x6apF2siaQ6PvgxqBXbGcKmgeD8mSIDO8= +github.com/crossplane/crossplane-runtime v0.19.2/go.mod h1:OJQ1NxtQK2ZTRmvtnQPoy8LsXsARTnVydRVDQEgIuz4= +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/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v24.0.4+incompatible h1:Y3bYF9ekNTm2VFz5U/0BlMdJy73D+Y1iAAZ8l63Ydzw= +github.com/docker/cli v24.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20200319173657-742aab907b54/go.mod h1:Oqz4IonmMNc2N7GqfTL2xkhCQx0yS6nR+HrOZJnmKIk= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20190219180918-740349757396 h1:XvFY2EbWlXUp7rS3wexKbH/p0KRaUJCzjWbsKdHggDQ= +github.com/docker/docker v1.4.2-0.20190219180918-740349757396/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +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/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= +github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +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/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +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/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsouza/go-dockerclient v1.3.6/go.mod h1:ptN6nXBwrXuiHAz2TYGOFCBB1aKGr371sGjMFdJEr1A= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v1.2.0/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/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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +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/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.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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 v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= +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.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.0.0-20190214194807-bada66e31e55/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk= +github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= +github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +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/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-20221102093814-76f304f74e5e h1:F1LLQqQ8WoIbyoxLUY+JUZe1kuHdxThM6CPUATzE6Io= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +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/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +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= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +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.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +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/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nightlyone/lockfile v0.0.0-20180618180623-0ad87eef1443/go.mod h1:JbxfV1Iifij2yhRjXai0oFrbpxszXHRx1E5RuM26o4Y= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +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.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +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/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +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/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= +github.com/vladimirvivien/gexe v0.2.0 h1:nbdAQ6vbZ+ZNsolCgSVb9Fno60kzSuvtzVh6Ytqi/xY= +github.com/vladimirvivien/gexe v0.2.0/go.mod h1:LHQL00w/7gDUKIak24n801ABp8C+ni6eBht9vGVst8w= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +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= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +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/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +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-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +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/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-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +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.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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +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.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/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-20190422165155-953cdadca894/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-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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-20210330210617-4fbd30eecc44/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-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.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/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.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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-20190328211700-ab21143f2384/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.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.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +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/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +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-20200513103714-09dca8ec2884/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 v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +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.28.1/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.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +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.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +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.27.1/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/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +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/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/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.0-20200615113413-eeeca48fe776/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= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +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.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= +k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= +k8s.io/apiextensions-apiserver v0.27.4 h1:ie1yZG4nY/wvFMIR2hXBeSVq+HfNzib60FjnBYtPGSs= +k8s.io/apiextensions-apiserver v0.27.4/go.mod h1:KHZaDr5H9IbGEnSskEUp/DsdXe1hMQ7uzpQcYUFt2bM= +k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= +k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= +k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= +k8s.io/component-base v0.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c= +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-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI= +k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ= +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.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= +sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= +sigs.k8s.io/e2e-framework v0.2.0 h1:gD6AWWAHFcHibI69E9TgkNFhh0mVwWtRCHy2RU057jQ= +sigs.k8s.io/e2e-framework v0.2.0/go.mod h1:E6JXj/V4PIlb95jsn2WrNKG+Shb45xaaI7C0+BH4PL8= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= +sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/docker/docker.go b/internal/docker/docker.go new file mode 100644 index 0000000..86d1425 --- /dev/null +++ b/internal/docker/docker.go @@ -0,0 +1,45 @@ +package docker + +import ( + "fmt" + "strings" + + "github.com/vladimirvivien/gexe" +) + +// Save runs docker save +func Save(image string, target string) error { + if len(image) == 0 || len(target) == 0 { + return fmt.Errorf("please provide source and target") + } + + return runDocker("save", image, "-o", target) +} + +// Cp runs docker cp +func Cp(src string, dest string) error { + if len(src) == 0 || len(dest) == 0 { + return fmt.Errorf("please provide source and target") + } + + return runDocker("cp", src, dest) +} + +// Exec runs docker exec +func Exec(container string, command string, options ...string) error { + if len(container) == 0 || len(command) == 0 { + return fmt.Errorf("please provide container and command") + } + + return runDocker("exec", append([]string{container, command}, options...)...) +} + +var runDocker = func(command string, options ...string) error { + proc := gexe.RunProc(fmt.Sprintf("docker %s %s", command, strings.Join(options, " "))) + + if proc.ExitCode() != 0 { + return fmt.Errorf("failed to execute 'docker %s': %s", command, proc.Result()) + } + + return nil +} diff --git a/internal/docker/docker_test.go b/internal/docker/docker_test.go new file mode 100644 index 0000000..259bbcb --- /dev/null +++ b/internal/docker/docker_test.go @@ -0,0 +1,280 @@ +package docker + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSave(t *testing.T) { + type args struct { + image string + target string + returnError error + } + type expects struct { + options []string + errorMessage string + } + + tests := []struct { + description string + args args + expects expects + }{ + { + description: "happy path", + args: args{ + image: "alpine", + target: "alpine.tar", + }, + expects: expects{ + options: []string{"alpine", "-o", "alpine.tar"}, + }, + }, + { + description: "returns an error if no args are given", + expects: expects{ + errorMessage: "please provide source and target", + }, + }, + { + description: "returns an error if image is empty", + args: args{ + target: "output.tar", + }, + expects: expects{ + errorMessage: "please provide source and target", + }, + }, + { + description: "returns an error if target is empty", + args: args{ + image: "alpine", + }, + expects: expects{ + errorMessage: "please provide source and target", + }, + }, + { + description: "returns an error if command can't be executed", + args: args{ + image: "ubuntu", + target: "out.tar", + returnError: fmt.Errorf("sth went wrong"), + }, + expects: expects{ + options: []string{"ubuntu", "-o", "out.tar"}, + errorMessage: "sth went wrong", + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + runDocker = func(command string, options ...string) error { + assert.Equal(t, "save", command) + assert.Equal(t, test.expects.options, options) + return test.args.returnError + } + + err := Save(test.args.image, test.args.target) + + if len(test.expects.errorMessage) == 0 { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, test.expects.errorMessage) + } + }) + } +} + +func TestCp(t *testing.T) { + type args struct { + source string + target string + returnError error + } + type expects struct { + options []string + errorMessage string + } + + tests := []struct { + description string + args args + expects expects + }{ + { + description: "happy path - copy from local to container", + args: args{ + source: "file.tar", + target: "dff106214482:/tmp/file.tar", + }, + expects: expects{ + options: []string{"file.tar", "dff106214482:/tmp/file.tar"}, + }, + }, + { + description: "happy path - copy from container to local", + args: args{ + source: "dff106214482:/tmp/file.tar", + target: "file.tar", + }, + expects: expects{ + options: []string{"dff106214482:/tmp/file.tar", "file.tar"}, + }, + }, + { + description: "returns an error if no args are given", + expects: expects{ + errorMessage: "please provide source and target", + }, + }, + { + description: "returns an error if image is empty", + args: args{ + target: "dff106214482:/home/ci/123.gz", + }, + expects: expects{ + errorMessage: "please provide source and target", + }, + }, + { + description: "returns an error if target is empty", + args: args{ + source: "some-file.txt", + }, + expects: expects{ + errorMessage: "please provide source and target", + }, + }, + { + description: "returns an error if command can't be executed", + args: args{ + source: "another-file.log", + target: "container-name:/var/log/another-file.log", + returnError: fmt.Errorf("sth went wrong"), + }, + expects: expects{ + options: []string{"another-file.log", "container-name:/var/log/another-file.log"}, + errorMessage: "sth went wrong", + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + runDocker = func(command string, options ...string) error { + assert.Equal(t, "cp", command) + assert.Equal(t, test.expects.options, options) + return test.args.returnError + } + + err := Cp(test.args.source, test.args.target) + + if len(test.expects.errorMessage) == 0 { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, test.expects.errorMessage) + } + }) + } +} + +func TestExec(t *testing.T) { + type args struct { + container string + command string + options []string + returnError error + } + type expects struct { + options []string + errorMessage string + } + + tests := []struct { + description string + args args + expects expects + }{ + { + description: "happy path - no options", + args: args{ + container: "some-container", + command: "whoami", + }, + expects: expects{ + options: []string{"some-container", "whoami"}, + }, + }, + { + description: "happy path - complex command", + args: args{ + container: "some-container", + command: "/bin/bash", + options: []string{"-c", "'find . -iname \"*.yaml\" -exec cat {} \\;'"}, + }, + expects: expects{ + options: []string{"some-container", "/bin/bash", "-c", "'find . -iname \"*.yaml\" -exec cat {} \\;'"}, + }, + }, + { + description: "returns an error if no args are given", + expects: expects{ + errorMessage: "please provide container and command", + }, + }, + { + description: "returns an error if container is not specified", + args: args{ + command: "ping", + }, + expects: expects{ + errorMessage: "please provide container and command", + }, + }, + { + description: "returns an error if command is not specified", + args: args{ + container: "some-container", + }, + expects: expects{ + errorMessage: "please provide container and command", + }, + }, + + { + description: "returns an error if command can't be executed", + args: args{ + container: "some-container", + command: "whoami", + returnError: fmt.Errorf("sth went wrong"), + }, + expects: expects{ + options: []string{"some-container", "whoami"}, + errorMessage: "sth went wrong", + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + runDocker = func(command string, options ...string) error { + assert.Equal(t, "exec", command) + assert.Equal(t, test.expects.options, options) + return test.args.returnError + } + + err := Exec(test.args.container, test.args.command, test.args.options...) + + if len(test.expects.errorMessage) == 0 { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, test.expects.errorMessage) + } + }) + } +} diff --git a/internal/xpkg/xpkg.go b/internal/xpkg/xpkg.go new file mode 100644 index 0000000..225a678 --- /dev/null +++ b/internal/xpkg/xpkg.go @@ -0,0 +1,56 @@ +package xpkg + +import ( + "bufio" + "compress/gzip" + "fmt" + "os" + + container "github.com/GoogleContainerTools/container-diff/pkg/util" +) + +var extractContainerImage = func(image string, path string) error { + _, err := container.GetImage(fmt.Sprintf("daemon://%s", image), false, path) + return err +} + +// FetchPackageContent returns the content of the package.yaml file from the givecn crossplane package +func FetchPackageContent(crossplanePackage string) (string, error) { + tmpDir, err := os.MkdirTemp("", "xpkg-*") + if err != nil { + return "", err + } + defer func(path string) { + _ = os.RemoveAll(path) + }(tmpDir) + + if err = extractContainerImage(crossplanePackage, tmpDir); err != nil { + return "", err + } + pkg, err := os.ReadFile(fmt.Sprintf("%s/package.yaml", tmpDir)) + if err != nil { + return "", err + } + return string(pkg), nil + +} + +// SavePackage saves the crossplane package descriptor of the given image gzipped to the specified target file +func SavePackage(crossplanePackage string, targetFile string) error { + pkg, err := FetchPackageContent(crossplanePackage) + if err != nil { + return err + } + // nolint: gosec + f, err := os.OpenFile(targetFile, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return err + } + + gzipWriter := gzip.NewWriter(f) + writer := bufio.NewWriter(gzipWriter) + _, _ = writer.WriteString(pkg) + _ = writer.Flush() + _ = gzipWriter.Close() + return f.Close() +} diff --git a/internal/xpkg/xpkg_test.go b/internal/xpkg/xpkg_test.go new file mode 100644 index 0000000..3e699d9 --- /dev/null +++ b/internal/xpkg/xpkg_test.go @@ -0,0 +1,164 @@ +package xpkg + +import ( + "bufio" + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +const csdProvider = `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: my-provider +spec: + package: my-provider + packagePullPolicy: Never` + +func returnStaticXPKG(t *testing.T, expectedImage string, returnContent string, returnError error) func(string, string) error { + return func(image string, path string) error { + assert.Equal(t, expectedImage, image) + + if returnError != nil { + return returnError + } + + f, err := os.OpenFile(fmt.Sprintf("%s/package.yaml", path), os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return err + } + + writer := bufio.NewWriter(f) + writer.WriteString(returnContent) + writer.Flush() + return f.Close() + } +} + +func TestFetchPackageContent(t *testing.T) { + type args struct { + crossplanePackage string + returnContent string + returnError error + } + type expects struct { + crossplanePackageContent string + errorMessage string + } + + tests := []struct { + description string + args args + expects expects + }{ + { + description: "happy path", + args: args{ + crossplanePackage: "build-7b9b1d70/crossplane/provider-abc", + returnContent: csdProvider, + }, + expects: expects{ + crossplanePackageContent: csdProvider, + }, + }, + { + description: "error case", + args: args{ + returnError: fmt.Errorf("sth went wrong"), + }, + expects: expects{ + errorMessage: "sth went wrong", + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + extractContainerImage = returnStaticXPKG(t, test.args.crossplanePackage, test.args.returnContent, test.args.returnError) + + pkgContent, err := FetchPackageContent(test.args.crossplanePackage) + + if len(test.expects.errorMessage) == 0 { + if assert.NoError(t, err) { + assert.Equal(t, test.expects.crossplanePackageContent, pkgContent) + } + } else { + assert.EqualError(t, err, test.expects.errorMessage) + } + }) + } +} + +func TestSavePackage(t *testing.T) { + type args struct { + crossplanePackage string + returnContent string + returnError error + } + type expects struct { + fileChecksum string + errorMessage string + } + + tests := []struct { + description string + args args + expects expects + }{ + { + description: "happy path", + args: args{ + crossplanePackage: "build-7b9b1d70/crossplane/provider-abc", + returnContent: csdProvider, + }, + expects: expects{ + fileChecksum: "36632d1c51a7eea28d69ce096747fc6ca3b130569dc4b4ff5b0e512954ac77fb", + }, + }, + { + description: "error case", + args: args{ + returnError: fmt.Errorf("sth went wrong"), + }, + expects: expects{ + errorMessage: "sth went wrong", + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + extractContainerImage = returnStaticXPKG(t, test.args.crossplanePackage, test.args.returnContent, test.args.returnError) + + if tmpFile, err := os.CreateTemp("", "test"); assert.NoError(t, err) { + defer os.Remove(tmpFile.Name()) + + err := SavePackage(test.args.crossplanePackage, tmpFile.Name()) + + if len(test.expects.errorMessage) == 0 { + if assert.NoError(t, err) { + assertSHA256(t, tmpFile.Name(), test.expects.fileChecksum) + } + } else { + assert.EqualError(t, err, test.expects.errorMessage) + } + } + }) + } +} + +func assertSHA256(t *testing.T, file string, expectedSHA256 string) { + if f, err := os.Open(file); assert.NoError(t, err) { + defer f.Close() + hasher := sha256.New() + + if _, err := io.Copy(hasher, f); assert.NoError(t, err) { + assert.Equal(t, expectedSHA256, hex.EncodeToString(hasher.Sum(nil))) + } + } +} diff --git a/pkg/conditions/conditions.go b/pkg/conditions/conditions.go new file mode 100644 index 0000000..890de33 --- /dev/null +++ b/pkg/conditions/conditions.go @@ -0,0 +1,46 @@ +package conditions + +import ( + "context" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + pkgv1 "github.com/crossplane/crossplane/apis/pkg/v1" + corev1 "k8s.io/api/core/v1" + apimachinerywait "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "sigs.k8s.io/e2e-framework/klient/k8s" + "sigs.k8s.io/e2e-framework/klient/k8s/resources" + apimachineryconditions "sigs.k8s.io/e2e-framework/klient/wait/conditions" +) + +// Conditions helps with matching resources on conditions +type Conditions struct { + apimachineryconditions.Condition + resources *resources.Resources +} + +// New is constructor for Conditions +func New(r *resources.Resources) *Conditions { + return &Conditions{resources: r} +} + +// ManagedResourceConditionMatch checks if a ManagedResource has a matching condition +func (c *Conditions) ManagedResourceConditionMatch( + provider k8s.Object, + conditionType xpv1.ConditionType, + conditionState corev1.ConditionStatus, +) apimachinerywait.ConditionFunc { + return func() (done bool, err error) { + klog.V(4).Infof("Awaiting provider %s to be ready", provider.GetName()) + if err := c.resources.Get(context.TODO(), provider.GetName(), provider.GetNamespace(), provider); err != nil { + return false, err + } + for _, cond := range provider.(*pkgv1.Provider).Status.Conditions { + klog.V(4).Infof("provider %s, condition: %s: %s", provider.GetName(), cond.Type, cond.Status) + if cond.Type == conditionType && cond.Status == conditionState { + done = true + } + } + return + } +} diff --git a/pkg/envvar/envvar.go b/pkg/envvar/envvar.go new file mode 100644 index 0000000..5f1ff9d --- /dev/null +++ b/pkg/envvar/envvar.go @@ -0,0 +1,33 @@ +package envvar + +import ( + "fmt" + "os" +) + +// Get is just a wrapper for os.Getenv +func Get(key string) string { + return os.Getenv(key) +} + +// GetOrDefault returns the environment variable or the default if its not available +func GetOrDefault(key string, defaultValue string) string { + return getOrDefault(key, func(key string) string { + return defaultValue + }) +} + +// GetOrPanic returns the environment variable or panics if its not available +func GetOrPanic(key string) string { + return getOrDefault(key, func(key string) string { + panic(fmt.Sprintf("environment variable '%s' couldn't be found", key)) + }) +} + +func getOrDefault(key string, defaultFn func(string) string) string { + if value, exists := os.LookupEnv(key); exists { + return value + } + + return defaultFn(key) +} diff --git a/pkg/envvar/envvar_test.go b/pkg/envvar/envvar_test.go new file mode 100644 index 0000000..d41bc2f --- /dev/null +++ b/pkg/envvar/envvar_test.go @@ -0,0 +1,69 @@ +package envvar + +import ( + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type EnvVarTestSuite struct { + suite.Suite +} + +func (suite *EnvVarTestSuite) SetupTest() { + os.Setenv("ENVVARTEST_EMPTY", "") + os.Setenv("ENVVARTEST_SINGLE", "This is a single line") + os.Setenv("ENVVARTEST_MULTILINE", `This +is +a multiline string!`) +} + +func (suite *EnvVarTestSuite) TearDownTest() { + for _, envvar := range os.Environ() { + if strings.HasPrefix(envvar, "ENVVARTEST_") { + os.Unsetenv(envvar) + } + } +} + +func (suite *EnvVarTestSuite) TestGet() { + suite.T().Run("Returns existing env vars", func(t *testing.T) { + assert.Equal(t, "", Get("ENVVARTEST_EMPTY")) + assert.Equal(t, "This is a single line", Get("ENVVARTEST_SINGLE")) + assert.Equal(t, "This\nis\na multiline string!", Get("ENVVARTEST_MULTILINE")) + }) + suite.T().Run("Returns empty string if env var can't be found", func(t *testing.T) { + assert.Empty(suite.T(), Get("ENVVARTEST_DOESNT_EXIST")) + }) +} + +func (suite *EnvVarTestSuite) TestGetOrDefault() { + suite.T().Run("Returns existing env vars", func(t *testing.T) { + assert.Equal(t, "", GetOrDefault("ENVVARTEST_EMPTY", "")) + assert.Equal(t, "This is a single line", GetOrDefault("ENVVARTEST_SINGLE", "")) + assert.Equal(t, "This\nis\na multiline string!", GetOrDefault("ENVVARTEST_MULTILINE", "")) + }) + suite.T().Run("Returns default value if env var can't be found", func(t *testing.T) { + assert.Equal(t, "a default value", GetOrDefault("ENVVARTEST_DOESNT_EXIST", "a default value")) + assert.Equal(t, "another default value", GetOrDefault("ENVVARTEST_DOESNT_EXIST", "another default value")) + }) +} + +func (suite *EnvVarTestSuite) TestGetOrPanic() { + suite.T().Run("Returns existing env vars", func(t *testing.T) { + assert.Equal(t, "", GetOrPanic("ENVVARTEST_EMPTY")) + assert.Equal(t, "This is a single line", GetOrPanic("ENVVARTEST_SINGLE")) + assert.Equal(t, "This\nis\na multiline string!", GetOrPanic("ENVVARTEST_MULTILINE")) + }) + suite.T().Run("Panics if env var can't be found", func(t *testing.T) { + assert.Panics(t, func() { GetOrPanic("ENVVARTEST_DOESNT_EXIST") }) + assert.Panics(t, func() { GetOrPanic("ENVVARTEST_DOESNT_EXIST") }) + }) +} + +func TestEnvVarTestSuite(t *testing.T) { + suite.Run(t, new(EnvVarTestSuite)) +} diff --git a/pkg/images/lookup.go b/pkg/images/lookup.go new file mode 100644 index 0000000..39193ac --- /dev/null +++ b/pkg/images/lookup.go @@ -0,0 +1,47 @@ +package images + +import ( + "encoding/json" + + "github.com/pkg/errors" + + "github.com/maximilianbraun/xp-testing/pkg/envvar" +) + +const ( + imagesJSONEnv = "TEST_IMAGES" +) + +// ProviderImages holds information to the docker images for providers +type ProviderImages struct { + Package string + ControllerImage *string +} + +// GetImagesFromJSONOrPanic retrieves image information from the environment and panics if `TEST_IMAGES` is not set +// `TEST_IMAGES` is expected to be a simple json like this. +// ```{"$PackageKey": "ImageUrlOfPackageImage", "$controllerKey": "ImageUrlOfControllerImage"}``` +// The controller image (key) is optional +func GetImagesFromJSONOrPanic(packageKey string, controllerKey *string) ProviderImages { + imagesJSON := envvar.GetOrPanic(imagesJSONEnv) + images := map[string]string{} + + err := json.Unmarshal([]byte(imagesJSON), &images) + + if err != nil { + panic(errors.Wrap(err, "failed to unmarshal json from UUT_IMAGE")) + } + + uutConfig := images[packageKey] + + var uutController *string + if controllerKey != nil { + val := images[*controllerKey] + uutController = &val + } + + return ProviderImages{ + Package: uutConfig, + ControllerImage: uutController, + } +} diff --git a/pkg/images/lookup_test.go b/pkg/images/lookup_test.go new file mode 100644 index 0000000..08298d5 --- /dev/null +++ b/pkg/images/lookup_test.go @@ -0,0 +1,52 @@ +package images + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type LookupSuite struct { + suite.Suite +} + +func TestLookupTestSuite(t *testing.T) { + suite.Run(t, new(LookupSuite)) +} + +func (suite *LookupSuite) TestGetImagesFromJSONOrPanic() { + packageKey := "foo" + controllerKey := "baz" + + suite.T().Run("Returns both images from environment", func(t *testing.T) { + err := os.Setenv("TEST_IMAGES", "{\"foo\": \"bar\", \"baz\": \"boom\"}") + println(err) + providerImages := GetImagesFromJSONOrPanic(packageKey, &controllerKey) + assert.Equal(t, "bar", providerImages.Package) + assert.Equal(t, "boom", *providerImages.ControllerImage) + }) + + suite.T().Run("Returns existing env vars", func(t *testing.T) { + os.Setenv("TEST_IMAGES", "{\"foo\": \"bar\"}") + providerImages := GetImagesFromJSONOrPanic(packageKey, nil) + assert.Equal(t, "bar", providerImages.Package) + assert.Nil(t, providerImages.ControllerImage) + }) + + suite.T().Run("env var not set, will panic", func(t *testing.T) { + os.Unsetenv("TEST_IMAGES") + assert.Panics(t, func() { + GetImagesFromJSONOrPanic(packageKey, nil) + }) + }) + + suite.T().Run("invalid json, will panic", func(t *testing.T) { + os.Setenv("TEST_IMAGES", "//invalid.json") + assert.Panics(t, func() { + GetImagesFromJSONOrPanic(packageKey, nil) + }) + }) + os.Unsetenv("TEST_IMAGES") +} diff --git a/pkg/logging/logging.go b/pkg/logging/logging.go new file mode 100644 index 0000000..76c1ebb --- /dev/null +++ b/pkg/logging/logging.go @@ -0,0 +1,36 @@ +package logging + +import ( + "flag" + "fmt" + + "k8s.io/klog/v2" +) + +const ( + verbosityLevel = "v" + logToStdErr = "alsologtostderr" +) + +// EnableVerboseLogging enables klog in verbosity of 4 if not overwritten by verbosity argument +func EnableVerboseLogging(verbosity *int) { + defaultVerbosity := 4 + effectiveVerbosity := defaultVerbosity + if verbosity != nil { + effectiveVerbosity = *verbosity + } + if flag.Lookup(verbosityLevel) == nil || flag.Lookup(logToStdErr) == nil { + klog.InitFlags(nil) + } + + if err := flag.Set(logToStdErr, fmt.Sprintf("%t", true)); err != nil { + panic(err) + } + + if err := flag.Set(verbosityLevel, fmt.Sprintf("%d", effectiveVerbosity)); err != nil { + panic(err) + } + + defer klog.Flush() + flag.Parse() +} diff --git a/pkg/logging/logging_test.go b/pkg/logging/logging_test.go new file mode 100644 index 0000000..aa3224d --- /dev/null +++ b/pkg/logging/logging_test.go @@ -0,0 +1,38 @@ +package logging + +import ( + "flag" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEnableVerboseLogging(t *testing.T) { + t.Run( + "default verbosity", func(t *testing.T) { + resetFlags() + EnableVerboseLogging(nil) + + verbseFlag := flag.Lookup("v") + assert.Equal(t, verbseFlag.Value.String(), "4") + }, + ) + t.Run( + "verbosity overwritten", func(t *testing.T) { + resetFlags() + + EnableVerboseLogging(ptr(10)) + + verbseFlag := flag.Lookup("v") + assert.Equal(t, verbseFlag.Value.String(), "10") + }, + ) +} + +func resetFlags() { + flag.CommandLine = flag.NewFlagSet("", flag.ContinueOnError) +} + +func ptr[T any](v T) *T { + return &v +} diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go new file mode 100644 index 0000000..dbe8133 --- /dev/null +++ b/pkg/resources/resources.go @@ -0,0 +1,358 @@ +package resources + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + "time" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/resource" + crossplanev1 "github.com/crossplane/crossplane/apis/pkg/v1" + "github.com/samber/lo" + v1 "k8s.io/api/core/v1" + v1extensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/e2e-framework/klient/decoder" + "sigs.k8s.io/e2e-framework/klient/k8s" + "sigs.k8s.io/e2e-framework/klient/k8s/resources" + "sigs.k8s.io/e2e-framework/klient/wait" + "sigs.k8s.io/e2e-framework/klient/wait/conditions" + "sigs.k8s.io/e2e-framework/pkg/envconf" +) + +// ImportResources gets the resources from ./data/crs +func ImportResources(ctx context.Context, t *testing.T, cfg *envconf.Config, dir string) { + r := resClient(cfg) + + r.WithNamespace(cfg.Namespace()) + + if exists, err := checkAtLeastOneYamlFile(dir); err != nil { + t.Fatal(err) + } else if !exists { + t.Fatalf("No yaml files found for %s", dir) + return + } + + // managed resources fare cluster scoped, so if we patched them with the test namespace it won't do anything + errdecode := decoder.DecodeEachFile( + ctx, os.DirFS(filepath.Join("./data/crs", dir)), "*", + decoder.CreateIgnoreAlreadyExists(r), + ) + if errdecode != nil { + t.Fatal(errdecode) + } +} + +func resClient(cfg *envconf.Config) *resources.Resources { + r, _ := GetResourcesWithRESTConfig(cfg) + return r +} + +// GetResourcesWithRESTConfig returns new resource from REST config +func GetResourcesWithRESTConfig(cfg *envconf.Config) (*resources.Resources, error) { + r, err := resources.New(cfg.Client().RESTConfig()) + return r, err +} + +func checkAtLeastOneYamlFile(dir string) (bool, error) { + files, err := filepath.Glob(filepath.Join("./data/crs", dir, "*.yaml")) + if err != nil { + return false, err + } + + return len(files) > 0, nil +} + +// WaitForResourcesToBeSynced waits until all managed resources are synced and available +func WaitForResourcesToBeSynced( + ctx context.Context, + cfg *envconf.Config, + dir string, + opts ...wait.Option, +) error { + objects, err := getObjectsToImport(ctx, cfg, dir) + if err != nil { + return err + } + + klog.V(4).Infof("Waiting for all objects to become on the following objects\n %s", identifiers(objects)) + + res := cfg.Client().Resources() + + err = wait.For( + conditions.New(res).ResourcesMatch(&mockList{Items: objects}, managedResourceSyncedAndAvailable), opts..., + ) + return err +} + +type mockList struct { + client.ObjectList + + Items []k8s.Object +} + +// Identifier returns k8s object name +func Identifier(object k8s.Object) string { + return fmt.Sprintf("%s/%s", object.GetObjectKind().GroupVersionKind().String(), object.GetName()) +} + +func identifiers(objects []k8s.Object) string { + val := "" + for _, object := range objects { + val = fmt.Sprintf("%s\n", Identifier(object)) + } + return val +} + +func managedResourceSyncedAndAvailable(object k8s.Object) bool { + managed, ok := object.(resource.Managed) + if !ok { + klog.V(4).Infof("Object (%s) is not a managed resource, treat as synced", Identifier(object)) + return true + } + + return managedCheckCondition(managed, xpv1.TypeSynced, v1.ConditionTrue) && + managedCheckCondition(managed, xpv1.TypeReady, v1.ConditionTrue) +} + +func managedCheckCondition(o resource.Managed, conditionType xpv1.ConditionType, want v1.ConditionStatus) bool { + got := o.GetCondition(conditionType).Status + return want == got +} + +func getObjectsToImport(ctx context.Context, cfg *envconf.Config, dir string) ([]k8s.Object, error) { + r := resClient(cfg) + + r.WithNamespace(cfg.Namespace()) + + objects := make([]k8s.Object, 0) + err := decoder.DecodeEachFile( + ctx, os.DirFS(filepath.Join("./data/crs", dir)), "*", + func(ctx context.Context, obj k8s.Object) error { + objects = append(objects, obj) + return nil + }, + ) + return objects, err +} + +// DumpManagedResources dumps resources with CRDs and Providers +func DumpManagedResources(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + resClient := resClient(cfg) + dumpWithCRDs(ctx, t, cfg, resClient) + dumpProviders(ctx, t, resClient) + return ctx +} + +func dumpProviders(ctx context.Context, t *testing.T, client *resources.Resources) { + var providers crossplanev1.ProviderList + + if err := crossplanev1.AddToScheme(client.GetScheme()); err != nil { + t.Fatal(err) + } + + if err := client.List(ctx, &providers); err != nil { + t.Fatal(err) + } + for _, provider := range providers.Items { + t.Log(provider) + } +} + +func dumpWithCRDs(ctx context.Context, t *testing.T, cfg *envconf.Config, client *resources.Resources) { + var crds v1extensions.CustomResourceDefinitionList + + if err := v1extensions.AddToScheme(client.GetScheme()); err != nil { + t.Fatal(err) + } + + if err := client.List(ctx, &crds); err != nil { + t.Fatal(err) + } + t.Log("Dumping all managed resources") + var relevantCRDs []v1extensions.CustomResourceDefinition + for _, crd := range crds.Items { + if lo.Contains(crd.Spec.Names.Categories, "managed") { + relevantCRDs = append(relevantCRDs, crd) + } + } + dynamiq := dynamic.NewForConfigOrDie(cfg.Client().RESTConfig()) + for _, crd := range relevantCRDs { + if crd.Spec.Scope == v1extensions.ClusterScoped { + for _, version := range crd.Spec.Versions { + dumpResourcesOfCRDs(ctx, t, dynamiq, crd, version) + } + } else { + t.Logf("Skipped %s, since its not cluster scoped", crd.Spec.Names.Kind) + } + } +} + +func getResourcesDynamically( + ctx context.Context, dynamic dynamic.Interface, + group string, version string, resource string, +) ( + []unstructured.Unstructured, error, +) { + + resourceID := schema.GroupVersionResource{ + Group: group, + Version: version, + Resource: resource, + } + list, err := dynamic.Resource(resourceID). + List(ctx, metav1.ListOptions{}) + + if err != nil { + return nil, err + } + + return list.Items, nil +} + +func dumpResourcesOfCRDs(ctx context.Context, t *testing.T, dynamiq dynamic.Interface, crd v1extensions.CustomResourceDefinition, version v1extensions.CustomResourceDefinitionVersion) { + resourcesList, err := getResourcesDynamically( + ctx, + dynamiq, + crd.Spec.Group, + version.Name, + crd.Spec.Names.Plural, + ) + if err != nil { + t.Error(err) + } + for _, res := range resourcesList { + t.Log(res) + } +} + +// DeleteResources deletes previously imported resources +func DeleteResources(ctx context.Context, t *testing.T, cfg *envconf.Config, manifestDir string, timeout wait.Option) context.Context { + klog.V(4).Info("Attempt to delete previously imported resources") + r, _ := GetResourcesWithRESTConfig(cfg) + objects, err := getObjectsToImport(ctx, cfg, manifestDir) + if err != nil { + t.Fatal(objects) + } + if err = deleteObjects(ctx, cfg, manifestDir); err != nil && !errors.IsNotFound(err) { + t.Fatal(err) + } + + if err = wait.For( + conditions.New(r).ResourcesDeleted(&mockList{Items: objects}), + timeout, + ); err != nil { + t.Fatal(err) + } + return ctx +} + +func deleteObjects(ctx context.Context, cfg *envconf.Config, dir string) error { + r := resClient(cfg) + r.WithNamespace(cfg.Namespace()) + + return decoder.DecodeEachFile( + ctx, os.DirFS(filepath.Join("./data/crs", dir)), "*", + decoder.DeleteHandler(r), + ) +} + +// AwaitResourceUpdateOrError waits for a given resource to update with a timeout of 3 minutes +func AwaitResourceUpdateOrError(ctx context.Context, t *testing.T, cfg *envconf.Config, object k8s.Object) { + AwaitResourceUpdateFor( + ctx, t, cfg, object, managedResourceSyncedAndAvailable, + wait.WithTimeout(time.Minute*3), + ) +} + +// AwaitResourceUpdateFor waits for a given resource to be updated +func AwaitResourceUpdateFor( + ctx context.Context, + t *testing.T, + cfg *envconf.Config, + object k8s.Object, + fn func(object k8s.Object) bool, + opts ...wait.Option, +) { + res := cfg.Client().Resources() + + err := res.Update(ctx, object) + if err != nil { + t.Fatal(err) + } + + err = wait.For( + conditions.New(res).ResourceMatch(object, fn), opts..., + ) + if err != nil { + t.Error(err) + } +} + +// AwaitResourceDeletionOrFail deletes a given k8s object with a timeout of 3 minutes +func AwaitResourceDeletionOrFail(ctx context.Context, t *testing.T, cfg *envconf.Config, object k8s.Object) { + res := cfg.Client().Resources() + + err := res.Delete(ctx, object) + if err != nil { + t.Fatalf("Failed to delete object %s.", Identifier(object)) + } + + err = wait.For(conditions.New(res).ResourceDeleted(object), wait.WithTimeout(time.Minute*3)) + if err != nil { + t.Fatalf( + "Failed to delete object in time %s.", + Identifier(object), + ) + } +} + +// ResourceTestConfig is a test configuration for a resource. +// It contains the kind of resource and the object to be tested +// and then provides basic CRD tests for the resource. +type ResourceTestConfig struct { + Kind string + Obj k8s.Object + AdditionalSteps map[string]func(context.Context, *testing.T, *envconf.Config) context.Context +} + +// Setup creates the resource in the cluster. +func (r *ResourceTestConfig) Setup(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + t.Logf("Apply %s", r.Kind) + ImportResources(ctx, t, cfg, r.Kind) + + return ctx +} + +// Teardown does nothing for now but exists here for completeness. +func (r *ResourceTestConfig) Teardown(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + return ctx +} + +// AssessCreate checks that the resource was created successfully. +func (r *ResourceTestConfig) AssessCreate(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + if err := WaitForResourcesToBeSynced(ctx, cfg, r.Kind, wait.WithTimeout(time.Minute*5)); err != nil { + DumpManagedResources(ctx, t, cfg) + t.Fatal(err) + } + return ctx +} + +// AssessUpdate does nothing for now but exists here for completeness. +func (r *ResourceTestConfig) AssessUpdate(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + return ctx +} + +// AssessDelete checks that the resource was deleted successfully. +func (r *ResourceTestConfig) AssessDelete(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + return DeleteResources(ctx, t, cfg, r.Kind, wait.WithTimeout(time.Minute*5)) +} diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go new file mode 100644 index 0000000..9cad454 --- /dev/null +++ b/pkg/setup/setup.go @@ -0,0 +1,105 @@ +package setup + +import ( + "os" + "strings" + + "github.com/crossplane/crossplane/apis/pkg/v1alpha1" + "github.com/vladimirvivien/gexe" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" + + "github.com/maximilianbraun/xp-testing/pkg/envvar" + "github.com/maximilianbraun/xp-testing/pkg/images" + "github.com/maximilianbraun/xp-testing/pkg/xenvfuncs" +) + +const ( + reuseClusterEnv = "TEST_REUSE_CLUSTER" + clusterNameEnv = "TEST_CLUSTER_NAME" + defaultPrefix = "e2e" +) + +// ClusterSetup help with a default kind setup for crossplane, with crossplane and a provider +type ClusterSetup struct { + Name string + Images images.ProviderImages + ControllerConfig v1alpha1.ControllerConfig + SecretData map[string]string + AddToSchemaFuncs []func(s *runtime.Scheme) error +} + +// Run optionally creates the kind cluster and takes care about the rest of the setup, +// There are two relevant Environment Variables that influence its behavior +// * TEST_REUSE_CLUSTER: if set, the cluster, crossplane and provider will be reused and not deleted after test. +// If set, CLUSTER_NAME will be ignored +// * TESTCLUSTER_NAME: overwrites the cluster name +func (s *ClusterSetup) Run(testEnv env.Environment) { + + reuseCluster := CheckEnvVarExists(reuseClusterEnv) + kindClusterName := clusterName(reuseCluster) + + firstSetup := true + if reuseCluster && clusterExists(kindClusterName) { + firstSetup = false + } + // Setup uses pre-defined funcs to create kind cluster + // and create a namespace for the environment + testEnv.Setup( + envfuncs.CreateKindCluster(kindClusterName), + xenvfuncs.Conditional(xenvfuncs.InstallCrossplane(kindClusterName), firstSetup), + xenvfuncs.Conditional( + xenvfuncs.InstallCrossplaneProvider( + kindClusterName, xenvfuncs.InstallCrossplaneProviderOptions{ + Name: s.Name, + Package: s.Images.Package, + ControllerImage: s.Images.ControllerImage, + ControllerConfig: &s.ControllerConfig, + }, + ), firstSetup, + ), + xenvfuncs.ApplySecretInCrossplaneNamespace("secret", s.SecretData), + xenvfuncs.CreateTestNamespace, + xenvfuncs.ApplyProviderConfig, + xenvfuncs.LoadSchemas(s.AddToSchemaFuncs...), + xenvfuncs.AwaitCRDsEstablished, + ) + + // Finish uses pre-defined funcs to + // remove namespace, then delete cluster + testEnv.Finish( + xenvfuncs.DumpKindLogs(kindClusterName), + xenvfuncs.DeleteTestNamespace, + xenvfuncs.Conditional(envfuncs.DestroyKindCluster(kindClusterName), !reuseCluster), + ) +} + +func clusterName(reuseCluster bool) string { + var kindClusterName string + if !reuseCluster && CheckEnvVarExists(clusterNameEnv) { + kindClusterName = envvar.GetOrDefault(clusterNameEnv, envconf.RandomName(defaultPrefix, 10)) + } else { + kindClusterName = defaultPrefix + } + return kindClusterName +} + +// TODO: Maybe part of the k8s-e2e framework? +func clusterExists(name string) bool { + e := gexe.New() + clusters := e.Run("kind get clusters") + for _, c := range strings.Split(clusters, "\n") { + if c == name { + return true + } + } + return false +} + +// CheckEnvVarExists returns if a environment variable exists +func CheckEnvVarExists(existsKey string) bool { + _, found := os.LookupEnv(existsKey) + return found +} diff --git a/pkg/xenvfuncs/xenvfuncs.go b/pkg/xenvfuncs/xenvfuncs.go new file mode 100644 index 0000000..e487e40 --- /dev/null +++ b/pkg/xenvfuncs/xenvfuncs.go @@ -0,0 +1,534 @@ +package xenvfuncs + +import ( + "bytes" + "context" + "crypto/sha256" + "fmt" + "io" + "os" + "path" + "strings" + "text/template" + "time" + + pkgv1 "github.com/crossplane/crossplane/apis/pkg/v1" + "github.com/crossplane/crossplane/apis/pkg/v1alpha1" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + v1extensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/e2e-framework/klient/decoder" + "sigs.k8s.io/e2e-framework/klient/k8s" + "sigs.k8s.io/e2e-framework/klient/k8s/resources" + "sigs.k8s.io/e2e-framework/klient/wait" + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" + "sigs.k8s.io/e2e-framework/third_party/helm" + "sigs.k8s.io/kind/pkg/cluster" + + xconditions "github.com/maximilianbraun/xp-testing/pkg/conditions" + resHelper "github.com/maximilianbraun/xp-testing/pkg/resources" + + "github.com/maximilianbraun/xp-testing/internal/docker" + "github.com/maximilianbraun/xp-testing/internal/xpkg" + "github.com/maximilianbraun/xp-testing/pkg/conditions" +) + +const crsCrossplaneCacheVolumeTemplate = `apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{.CacheVolume}} + labels: + type: local +spec: + storageClassName: manual + capacity: + storage: 5Mi + accessModes: + - ReadWriteOnce + hostPath: + path: "{{.CacheMount}}" +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{.CacheVolume}} + namespace: crossplane-system +spec: + accessModes: + - ReadWriteOnce + volumeName: {{.CacheVolume}} + storageClassName: manual + resources: + requests: + storage: 1Mi` + +const crsCrossplaneProviderTemplate = `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: {{.Name}} +spec: + package: {{.Name}} + packagePullPolicy: Never + {{- if .ControllerConfig }} + controllerConfigRef: + name: {{.ControllerConfig}} +{{end}}` + +const ( + helmRepoName = "e2e_crossplane-stable" + // CrossplaneNamespace the namespace crossplane will be installed to + CrossplaneNamespace = "crossplane-system" + clusterNameKey = "clusterNameType" +) + +var ( + // The default key to put the cluster name into context + defaultClusterKey = clusterNameType(clusterNameKey) +) + +type clusterNameType string + +// InstallCrossplane returns an env.Func that is used to install crossplane into the given cluster +func InstallCrossplane(clusterName string) env.Func { // TODO specify version + cacheName := "package-cache" + + return Compose( + envfuncs.CreateNamespace(CrossplaneNamespace), + setupCrossplanePackageCache(clusterName, cacheName), + func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + kindCluster, ok := envfuncs.GetKindClusterFromContext(ctx, clusterName) + if !ok { + return ctx, fmt.Errorf("install crossplane func: cluster '%s' doesn't exist", clusterName) + } + + manager := helm.New(kindCluster.GetKubeconfig()) + if err := manager.RunRepo( + helm.WithArgs( + "add", + helmRepoName, + "https://charts.crossplane.io/stable", + "--force-update", + ), + ); err != nil { + return ctx, errors.Wrap(err, "install crossplane func: failed to add crossplane helm chart repo") + } + if err := manager.RunRepo(helm.WithArgs("update")); err != nil { + return ctx, errors.Wrap(err, "install crossplane func: failed to upgrade helm repo") + } + + helmInstallOpts := []helm.Option{ + helm.WithName("crossplane"), + helm.WithNamespace("crossplane-system"), + helm.WithReleaseName(helmRepoName + "/crossplane"), + helm.WithArgs("--set", fmt.Sprintf("packageCache.pvc=%s", cacheName)), + helm.WithWait(), + helm.WithTimeout("10m"), + } + + // TODO set target crossplane version + + if err := manager.RunInstall(helmInstallOpts...); err != nil { + return ctx, errors.Wrap(err, "install crossplane func: failed to install crossplane Helm chart") + } + + return ctx, nil + }, + ) +} + +// ApplySecretInCrossplaneNamespace creates secret that is used by providers in the crossplane namespace +func ApplySecretInCrossplaneNamespace(name string, data map[string]string) env.Func { + return Compose( + func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + r, err := resources.New(cfg.Client().RESTConfig()) + + if err != nil { + klog.Error(err) + return ctx, err + } + + secret := newSecret(name, data) + + if err := r.Create(ctx, secret); err != nil { + klog.Error(err) + return ctx, err + } + + return ctx, nil + }, + ) +} + +// InstallCrossplaneProviderOptions hols information on the tested provider +type InstallCrossplaneProviderOptions struct { + Name string + Package string + ControllerImage *string // TODO read from package + ControllerConfig *v1alpha1.ControllerConfig +} + +// InstallCrossplaneProvider returns an env.Func that is used to +// install a crossplane provider into the active cluster +func InstallCrossplaneProvider(clusterName string, opts InstallCrossplaneProviderOptions) env.Func { + return Compose( + loadCrossplanePackageToCluster(clusterName, opts), + loadCrossplaneControllerImageToCluster(clusterName, opts), + installCrossplaneProviderEnvFunc(clusterName, opts), + awaitProviderHealthy(opts), + ) +} + +// ApplyProviderConfig applys the files from `./data/provider` and mutates their namespace +func ApplyProviderConfig(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + r, _ := resources.New(cfg.Client().RESTConfig()) + + klog.Info("Apply ProviderConfig") + errDecode := decoder.DecodeEachFile( + ctx, os.DirFS("./data/provider"), "*", + decoder.CreateHandler(r), + decoder.MutateNamespace(cfg.Namespace()), + ) + + if errDecode != nil { + klog.Error("Error Details", "errDecode", errDecode) + } + + return ctx, nil +} + +// LoadSchemas prepares the kubernetes client with additional schemas +func LoadSchemas(addToSchemaFuncs ...func(s *runtime.Scheme) error) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + r, err := resources.New(cfg.Client().RESTConfig()) + if err != nil { + return ctx, err + } + for _, addToSchemaFunc := range addToSchemaFuncs { + if err = addToSchemaFunc(r.GetScheme()); err != nil { + return ctx, err + } + } + + if err = v1extensions.AddToScheme(r.GetScheme()); err != nil { + return ctx, err + } + + if err = corev1.AddToScheme(r.GetScheme()); err != nil { + return ctx, err + } + + return ctx, nil + } +} + +// setupCrossplanePackageCache prepares the crossplane package-cache in the given clusters control plane +func setupCrossplanePackageCache(clusterName string, cacheName string) env.Func { + cacheMount := "/cache" + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + controlPlaneName := getClusterControlPlaneName(clusterName) + + if err := docker.Exec(controlPlaneName, "mkdir", "-m", "777", "-p", cacheMount); err != nil { + return ctx, err + } + + rendered, err := renderTemplate( + crsCrossplaneCacheVolumeTemplate, struct { + CacheVolume string + CacheMount string + }{ + CacheVolume: cacheName, + CacheMount: cacheMount, + }, + ) + + if err != nil { + return ctx, err + } + + return applyResources(ctx, cfg, rendered) + } +} + +// loadCrossplanePackageToCluster loads the crossplane config package into the given clusters package cache folder (/cache) +func loadCrossplanePackageToCluster(clusterName string, opts InstallCrossplaneProviderOptions) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + f, err := os.CreateTemp("", "xpkg") + if err != nil { + return ctx, err + } + defer func(name string) { + _ = os.Remove(name) + }(f.Name()) + + clusterControlPlaneName := getClusterControlPlaneName(clusterName) + + if err = xpkg.SavePackage(opts.Package, f.Name()); err != nil { + return ctx, err + } + + cachePackagePath := fmt.Sprintf("/cache/%s.gz", opts.Name) + + if err = docker.Cp(f.Name(), fmt.Sprintf("%s:%s", clusterControlPlaneName, cachePackagePath)); err != nil { + return ctx, err + } + + return ctx, docker.Exec(clusterControlPlaneName, "chmod", "644", cachePackagePath) + } +} + +// loadCrossplaneControllerImageToCluster loads the controller image into the oci cache of the given cluster +func loadCrossplaneControllerImageToCluster(clusterName string, opts InstallCrossplaneProviderOptions) env.Func { + if opts.ControllerImage == nil { + // no-op + return func(ctx context.Context, config *envconf.Config) (context.Context, error) { + return ctx, nil + } + } + return envfuncs.LoadDockerImageToCluster(clusterName, *opts.ControllerImage) +} + +// installCrossplaneProviderEnvFunc is an env.Func to install a crossplane provider into the given cluster +func installCrossplaneProviderEnvFunc(_ string, opts InstallCrossplaneProviderOptions) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + + data := struct { + Name string + Package string + ControllerConfig string + }{ + Name: opts.Name, + Package: opts.Package, + } + + if opts.ControllerConfig != nil { + config := opts.ControllerConfig.DeepCopy() + config.ObjectMeta = metav1.ObjectMeta{ + Name: opts.Name, + } + data.ControllerConfig = opts.Name + res := cfg.Client().Resources() + if err := v1alpha1.AddToScheme(res.GetScheme()); err != nil { + return ctx, err + } + err := res.Create(ctx, config) + if err != nil { + return nil, err + } + } + + crs, err := renderTemplate( + crsCrossplaneProviderTemplate, data, + ) + + if err != nil { + return ctx, err + } + return applyResources(ctx, cfg, crs) + } +} + +func awaitProviderHealthy(opts InstallCrossplaneProviderOptions) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + provider := pkgv1.Provider{ + ObjectMeta: metav1.ObjectMeta{Name: opts.Name}, + } + r, err := resources.New(cfg.Client().RESTConfig()) + if err != nil { + return ctx, err + } + if err := pkgv1.AddToScheme(r.GetScheme()); err != nil { + return ctx, err + } + err = wait.For( + xconditions.New(r).ManagedResourceConditionMatch( + &provider, + pkgv1.TypeHealthy, + corev1.ConditionTrue, + ), wait.WithTimeout(time.Minute*5), + ) + return ctx, err + } +} + +// applyResources is an equivalent for kubectl apply +func applyResources(ctx context.Context, cfg *envconf.Config, crs string) (context.Context, error) { + r, err := resources.New(cfg.Client().RESTConfig()) + if err != nil { + return ctx, err + } + + return ctx, decoder.DecodeEach(ctx, strings.NewReader(crs), decoder.CreateHandler(r)) +} + +// getClusterControlPlaneName returns the supposed name of the given clusters control plane +func getClusterControlPlaneName(clusterName string) string { + return fmt.Sprintf("%s-control-plane", clusterName) +} + +// Compose executes multiple env.Funcs in a row +func Compose(envfuncs ...env.Func) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + for _, envfunc := range envfuncs { + if ctx, err := envfunc(ctx, cfg); err != nil { + return ctx, err + } + } + return ctx, nil + } +} + +func renderTemplate(tmpl string, data interface{}) (string, error) { + h := sha256.New() + _, _ = io.WriteString(h, tmpl) + + hash := string(h.Sum(nil)) + + parsedTmpl, err := template.New(hash).Parse(tmpl) + if err != nil { + return "", err + } + + buf := bytes.Buffer{} + if err := parsedTmpl.Execute(&buf, data); err != nil { + return "", err + } + + return buf.String(), nil +} + +// IgnoreErr exec's fn, logs possible error away continues w/o error +func IgnoreErr(fn env.Func) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + if _, err := fn(ctx, cfg); err != nil { + klog.V(4).Info(err) + } + return ctx, nil + } + +} + +// Conditional executes a fn based on conditional +func Conditional(fn env.Func, condition bool) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + if condition { + return fn(ctx, cfg) + } + return ctx, nil + } +} + +// Create Opaque secret from non-binary data in crossplane namespace +func newSecret(name string, stringData map[string]string) *corev1.Secret { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: CrossplaneNamespace, + }, + StringData: stringData, + Type: corev1.SecretTypeOpaque, + } + + return secret +} + +// AwaitCRDsEstablished waits until all CRDs do have a condition `Established` == true +func AwaitCRDsEstablished(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + client, err := resources.New(cfg.Client().RESTConfig()) + if err != nil { + return ctx, err + } + var crds v1extensions.CustomResourceDefinitionList + + if err := client.List(ctx, &crds); err != nil { + return ctx, err + } + + err = wait.For( + conditions.New(client).ResourcesMatch(&crds, crdIsEstablished), wait.WithTimeout(time.Minute), + ) + return ctx, err +} + +func crdIsEstablished(object k8s.Object) bool { + crd, ok := object.(*v1extensions.CustomResourceDefinition) + if !ok { + panic("No CRD with this object") + } + + for _, condition := range crd.Status.Conditions { + if condition.Type != v1extensions.Established { + continue + } + want := v1extensions.ConditionTrue + got := condition.Status + + klog.V(4).Infof( + "Checking resource (%s) condition %s, got %s, want %s", + resHelper.Identifier(crd), + v1extensions.Established, + got, + want, + ) + return got == want + + } + return false +} + +// DumpKindLogs Dumps the logs of the cluster to `$PWD/logs` using kind export func +func DumpKindLogs(clusterName string) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + provider := cluster.NewProvider() + dir, err := os.Getwd() + if err != nil { + return ctx, err + } + effectivePath := path.Join(dir, "logs") + klog.Infof("Writing kind logs to %s", effectivePath) + err = provider.CollectLogs(clusterName, effectivePath) + + return ctx, err + } +} + +// DumpKubernetesLogs Dumps the logs of the cluster to `$PWD/logs-$identifier` using kind export func +func DumpKubernetesLogs(ctx context.Context, identifier string) (context.Context, error) { + provider := cluster.NewProvider() + dir, err := os.Getwd() + if err != nil { + return ctx, err + } + clusterName, ok := ctx.Value(defaultClusterKey).(string) + if !ok { + return ctx, errors.New("cluster not found in test context") + } + effectivePath := path.Join(dir, fmt.Sprintf("logs-%s", identifier)) + klog.Infof("Writing kind logs to %s", effectivePath) + err = provider.CollectLogs(clusterName, effectivePath) + + return ctx, err +} + +// SetClusterName Sets the name of the cluster into context to retrieve it by other functions +func SetClusterName(clusterName string) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + ctx = context.WithValue(ctx, defaultClusterKey, clusterName) + + return ctx, nil + } +} + +// CreateTestNamespace Creates the test namespace, name comes from kubernetes-e2e +func CreateTestNamespace(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + return envfuncs.CreateNamespace(cfg.Namespace())(ctx, cfg) +} + +// DeleteTestNamespace Deletes the test namespace, name comes from kubernetes-e2e +func DeleteTestNamespace(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + return envfuncs.DeleteNamespace(cfg.Namespace())(ctx, cfg) +} diff --git a/pkg/xenvfuncs/xenvfuncs_test.go b/pkg/xenvfuncs/xenvfuncs_test.go new file mode 100644 index 0000000..27a8804 --- /dev/null +++ b/pkg/xenvfuncs/xenvfuncs_test.go @@ -0,0 +1,294 @@ +package xenvfuncs + +import ( + "context" + "fmt" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" +) + +func TestCompose(t *testing.T) { + incEnvFunc := func(i *int) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + *i++ + return ctx, nil + } + } + + errEnvFunc := func(err error) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + return ctx, err + } + } + + t.Run( + "nop", func(t *testing.T) { + pctx := context.Background() + + ctx, err := Compose()(pctx, nil) + + assert.NoError(t, err) + assert.Equal(t, pctx, ctx) + }, + ) + + t.Run( + "passes ctx and cfg to child envfunc", func(t *testing.T) { + invoked := false + + pctx := context.Background() + pcfg := &envconf.Config{} + + ctx, err := Compose( + func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + invoked = true + assert.Equal(t, pctx, ctx) + assert.Equal(t, pcfg, cfg) + return ctx, nil + }, + )(pctx, pcfg) + + assert.True(t, invoked) + assert.NoError(t, err) + assert.Equal(t, pctx, ctx) + }, + ) + + t.Run( + "invokes all configured child funcs", func(t *testing.T) { + invocations := 0 + + _, err := Compose( + incEnvFunc(&invocations), + incEnvFunc(&invocations), + incEnvFunc(&invocations), + )(context.Background(), &envconf.Config{}) + + assert.NoError(t, err) + assert.Equal(t, 3, invocations) + }, + ) + + t.Run( + "stops processing in case of error", func(t *testing.T) { + invocations := 0 + + _, err := Compose( + incEnvFunc(&invocations), + incEnvFunc(&invocations), + errEnvFunc(fmt.Errorf("stop here")), + incEnvFunc(&invocations), + )(context.Background(), &envconf.Config{}) + + assert.EqualError(t, err, "stop here") + assert.Equal(t, 2, invocations) + }, + ) +} + +func TestGetClusterControlPlaneName(t *testing.T) { + assert.Equal(t, "my-cluster-control-plane", getClusterControlPlaneName("my-cluster")) +} + +func TestRenderTemplate(t *testing.T) { + type args struct { + template string + data interface{} + } + type expects struct { + rendered string + errorMessage string + } + + tests := []struct { + description string + args args + expects expects + }{ + { + description: "nop", + }, + { + description: "simple string without replacements", + args: args{ + template: "This is a simple string and nothing should be replaced!", + }, + expects: expects{ + rendered: "This is a simple string and nothing should be replaced!", + }, + }, + { + description: "simple string with single replacement", + args: args{ + template: "Hello {{.Subject}}!", + data: struct { + Subject string + }{ + Subject: "World", + }, + }, + expects: expects{ + rendered: "Hello World!", + }, + }, + { + description: "multiline string with multiple replacements", + args: args{ + template: `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: {{.Name}} +spec: + package: {{.Package}} + packagePullPolicy: Never`, + data: struct { + Name string + Package string + }{ + Name: "my-provider", + Package: "my-registry.local/path/to/my-provider:1.2.3", + }, + }, + expects: expects{ + rendered: `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: my-provider +spec: + package: my-registry.local/path/to/my-provider:1.2.3 + packagePullPolicy: Never`, + }, + }, + { + description: "multiline string with condition is true", + args: args{ + template: `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: {{.Name}} +spec: + package: {{.Package}} + packagePullPolicy: Never + {{- if .ControllerConfig }} + controllerConfigRef: + name: {{.ControllerConfig}} +{{end}}`, + data: struct { + Name string + Package string + ControllerConfig string + }{ + Name: "my-provider", + Package: "my-registry.local/path/to/my-provider:1.2.3", + ControllerConfig: "my-controller-config-ref", + }, + }, + expects: expects{ + rendered: `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: my-provider +spec: + package: my-registry.local/path/to/my-provider:1.2.3 + packagePullPolicy: Never + controllerConfigRef: + name: my-controller-config-ref +`, + }, + }, + { + description: "multiline string with condition is false", + args: args{ + template: `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: {{.Name}} +spec: + package: {{.Package}} + packagePullPolicy: Never + {{- if .ControllerConfig }} + controllerConfigRef: + name: {{.ControllerConfig}} +{{end}}`, + data: struct { + Name string + Package string + ControllerConfig string + }{ + Name: "my-provider", + Package: "my-registry.local/path/to/my-provider:1.2.3", + }, + }, + expects: expects{ + rendered: `apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: my-provider +spec: + package: my-registry.local/path/to/my-provider:1.2.3 + packagePullPolicy: Never`, + }, + }, + } + + for _, test := range tests { + t.Run( + test.description, func(t *testing.T) { + assert.True(t, true) + rendered, err := renderTemplate(test.args.template, test.args.data) + + if len(test.expects.errorMessage) == 0 { + if assert.NoError(t, err) { + assert.Equal(t, test.expects.rendered, rendered) + } + } else { + assert.Error(t, err) + } + }, + ) + } +} + +var dummyErrFunc = func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + return ctx, errors.New("dummy err") +} + +func TestDummyErr(t *testing.T) { + t.Run( + "dummyErrFunc returns error", func(t *testing.T) { + _, err := dummyErrFunc(nil, nil) + assert.Error(t, err) + }, + ) +} + +func TestConditional(t *testing.T) { + t.Run( + "executes", func(t *testing.T) { + conditionalFn := Conditional(dummyErrFunc, true) + _, err := conditionalFn(nil, nil) + assert.Error(t, err) + }, + ) + t.Run( + "doesnt execute", func(t *testing.T) { + conditionalFn := Conditional(dummyErrFunc, false) + _, err := conditionalFn(nil, nil) + assert.NoError(t, err) + }, + ) +} + +func TestIgnoreErr(t *testing.T) { + t.Run( + "no error thown", func(t *testing.T) { + conditionalFn := IgnoreErr(dummyErrFunc) + _, err := conditionalFn(nil, nil) + assert.NoError(t, err) + }, + ) +} From 12d1c39da002223b265acb2b680721f127685874 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 00:23:14 +0200 Subject: [PATCH 04/23] go mod fixup Signed-off-by: Maximilian Braun (SAP) --- go.mod | 6 +++--- go.sum | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 452aa48..81d1c80 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/GoogleContainerTools/container-diff v0.17.0 - github.com/crossplane/crossplane v0.0.0-00010101000000-000000000000 + github.com/crossplane/crossplane v1.11.5 github.com/crossplane/crossplane-runtime v0.19.2 github.com/pkg/errors v0.9.1 github.com/samber/lo v1.38.1 @@ -91,8 +91,8 @@ require ( sigs.k8s.io/yaml v1.3.0 // indirect ) -replace github.com/crossplane/crossplane => github.com/crossplane/crossplane v1.11.3 +replace github.com/crossplane/crossplane => github.com/crossplane/crossplane v1.11.5 -replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.19.2 +replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.18.0 replace github.com/docker/docker => github.com/docker/docker v1.4.2-0.20190219180918-740349757396 diff --git a/go.sum b/go.sum index 19d53fa..7724f35 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crossplane/crossplane v1.11.3 h1:nvV8ivMZd98zSr7SLsu4IFNbQg4c+YvdgxwvbtxSnL8= github.com/crossplane/crossplane v1.11.3/go.mod h1:EV76e/7nJ8tJ+wrpx+2nKNMEic92iI13n4RwfI4Pgy0= -github.com/crossplane/crossplane-runtime v0.19.2 h1:9qBnhpqKN4x6apF2siaQ6PvgxqBXbGcKmgeD8mSIDO8= -github.com/crossplane/crossplane-runtime v0.19.2/go.mod h1:OJQ1NxtQK2ZTRmvtnQPoy8LsXsARTnVydRVDQEgIuz4= +github.com/crossplane/crossplane v1.11.5 h1:It/kq9VeO2dLy9kU95RJDJup9N0WEqiATmVMqcOci6Y= +github.com/crossplane/crossplane v1.11.5/go.mod h1:HhJ/EVMdbbZD5NuwJ32F1TSjaaiD6jPveP/qNghZiyk= +github.com/crossplane/crossplane-runtime v0.18.0 h1:j1VxhKWp3iQKr1XNiMoBKmEvN2Z98E7rR0tyimu7dj4= +github.com/crossplane/crossplane-runtime v0.18.0/go.mod h1:o9ExoilV6k2M3qzSFoRVX4phuww0mLmjs1WrDTvsR4s= 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= From 021de22a402da55d93a1a04afa662cd7facf9c3c Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 07:57:32 +0200 Subject: [PATCH 05/23] workflows Signed-off-by: Maximilian Braun (SAP) --- .github/workflows/codeql.yml | 8 ++++++-- .golangci.yml | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2e50bcf..c836661 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,9 +34,13 @@ jobs: submodules: true - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 + + - name: Upload CodeQL Analysis + uses: github/codeql-action/upload-sarif@v2 + diff --git a/.golangci.yml b/.golangci.yml index 3c0aaca..91be78a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -38,7 +38,7 @@ linters-settings: goimports: # put imports beginning with prefix after 3rd-party packages; # it's a comma-separated list of prefixes - local-prefixes: github.tools.sap/cloud-orchestration/managed-control-plane-operator + local-prefixes: gocyclo: # minimal code complexity to report, 30 by default (but we recommend 10-20) @@ -197,4 +197,4 @@ issues: max-per-linter: 0 # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. - max-same-issues: 0 \ No newline at end of file + max-same-issues: 0 From 27837afcba7e5ae4d43383214b52b1469a66afe8 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 08:02:52 +0200 Subject: [PATCH 06/23] fixup deps Signed-off-by: Maximilian Braun (SAP) --- go.mod | 4 ++-- go.sum | 33 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 81d1c80..c9d5d5a 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( k8s.io/apimachinery v0.27.4 k8s.io/client-go v0.27.4 k8s.io/klog/v2 v2.100.1 - sigs.k8s.io/controller-runtime v0.15.0 + sigs.k8s.io/controller-runtime v0.14.6 sigs.k8s.io/e2e-framework v0.2.0 sigs.k8s.io/kind v0.20.0 ) @@ -93,6 +93,6 @@ require ( replace github.com/crossplane/crossplane => github.com/crossplane/crossplane v1.11.5 -replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.18.0 +replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.19.2 replace github.com/docker/docker => github.com/docker/docker v1.4.2-0.20190219180918-740349757396 diff --git a/go.sum b/go.sum index 7724f35..8a4400e 100644 --- a/go.sum +++ b/go.sum @@ -90,12 +90,10 @@ github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNA github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/crossplane/crossplane v1.11.3 h1:nvV8ivMZd98zSr7SLsu4IFNbQg4c+YvdgxwvbtxSnL8= -github.com/crossplane/crossplane v1.11.3/go.mod h1:EV76e/7nJ8tJ+wrpx+2nKNMEic92iI13n4RwfI4Pgy0= github.com/crossplane/crossplane v1.11.5 h1:It/kq9VeO2dLy9kU95RJDJup9N0WEqiATmVMqcOci6Y= github.com/crossplane/crossplane v1.11.5/go.mod h1:HhJ/EVMdbbZD5NuwJ32F1TSjaaiD6jPveP/qNghZiyk= -github.com/crossplane/crossplane-runtime v0.18.0 h1:j1VxhKWp3iQKr1XNiMoBKmEvN2Z98E7rR0tyimu7dj4= -github.com/crossplane/crossplane-runtime v0.18.0/go.mod h1:o9ExoilV6k2M3qzSFoRVX4phuww0mLmjs1WrDTvsR4s= +github.com/crossplane/crossplane-runtime v0.19.2 h1:9qBnhpqKN4x6apF2siaQ6PvgxqBXbGcKmgeD8mSIDO8= +github.com/crossplane/crossplane-runtime v0.19.2/go.mod h1:OJQ1NxtQK2ZTRmvtnQPoy8LsXsARTnVydRVDQEgIuz4= 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= @@ -129,6 +127,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= 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/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= @@ -147,7 +146,7 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logr/logr v1.2.0/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/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= 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= @@ -155,7 +154,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En 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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -317,10 +316,10 @@ github.com/nightlyone/lockfile v0.0.0-20180618180623-0ad87eef1443/go.mod h1:Jbxf github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -342,18 +341,18 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 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.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -655,7 +654,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= 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= @@ -723,7 +722,7 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -745,7 +744,7 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= 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= @@ -813,8 +812,8 @@ k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt 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.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= -sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= +sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA= +sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= sigs.k8s.io/e2e-framework v0.2.0 h1:gD6AWWAHFcHibI69E9TgkNFhh0mVwWtRCHy2RU057jQ= sigs.k8s.io/e2e-framework v0.2.0/go.mod h1:E6JXj/V4PIlb95jsn2WrNKG+Shb45xaaI7C0+BH4PL8= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= From 962722e0df6f2c303be9e8bb7442d951f2e7cb24 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 08:27:14 +0200 Subject: [PATCH 07/23] permissions for codeql Signed-off-by: Maximilian Braun (SAP) --- .github/workflows/codeql.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c836661..1c23014 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -7,6 +7,11 @@ on: - release-* workflow_dispatch: {} +permissions: + actions: read + contents: read + security-events: write + jobs: detect-noop: runs-on: ubuntu-20.04 From f9d79cd9af6b5307e45ee2f28ef5adb8313c2630 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 08:49:24 +0200 Subject: [PATCH 08/23] cleanup Signed-off-by: Maximilian Braun (SAP) --- .github/workflows/codeql.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1c23014..d05f36c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,6 +46,3 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 - - name: Upload CodeQL Analysis - uses: github/codeql-action/upload-sarif@v2 - From f2ed481efa37539214e3b5d60152566b03fb7674 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 08:52:28 +0200 Subject: [PATCH 09/23] moving codeql torwards gh workflow template Signed-off-by: Maximilian Braun (SAP) --- .github/workflows/codeql.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d05f36c..20f9045 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,11 +1,16 @@ name: CodeQL on: + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] push: branches: - main - release-* workflow_dispatch: {} + schedule: + - cron: '27 2 * * 0' permissions: actions: read @@ -43,6 +48,10 @@ jobs: with: languages: go + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 - + with: + category: "/language:go" From d69117e9aaa467775a14284de1ab9a957837cfe3 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 11 Aug 2023 23:41:07 +0200 Subject: [PATCH 10/23] test setup Signed-off-by: Maximilian Braun (SAP) --- pkg/setup/setup.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 9cad454..79f7108 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -7,6 +7,7 @@ import ( "github.com/crossplane/crossplane/apis/pkg/v1alpha1" "github.com/vladimirvivien/gexe" "k8s.io/apimachinery/pkg/runtime" + log "k8s.io/klog/v2" "sigs.k8s.io/e2e-framework/pkg/env" "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" @@ -17,8 +18,8 @@ import ( ) const ( - reuseClusterEnv = "TEST_REUSE_CLUSTER" - clusterNameEnv = "TEST_CLUSTER_NAME" + reuseClusterEnv = "E2E_REUSE_CLUSTER" + clusterNameEnv = "E2E_CLUSTER_NAME" defaultPrefix = "e2e" ) @@ -26,25 +27,29 @@ const ( type ClusterSetup struct { Name string Images images.ProviderImages - ControllerConfig v1alpha1.ControllerConfig + ControllerConfig *v1alpha1.ControllerConfig SecretData map[string]string AddToSchemaFuncs []func(s *runtime.Scheme) error } -// Run optionally creates the kind cluster and takes care about the rest of the setup, +// Configure optionally creates the kind cluster and takes care about the rest of the setup, // There are two relevant Environment Variables that influence its behavior -// * TEST_REUSE_CLUSTER: if set, the cluster, crossplane and provider will be reused and not deleted after test. +// * E2E_REUSE_CLUSTER: if set, the cluster, crossplane and provider will be reused and not deleted after test. // If set, CLUSTER_NAME will be ignored // * TESTCLUSTER_NAME: overwrites the cluster name -func (s *ClusterSetup) Run(testEnv env.Environment) { +func (s *ClusterSetup) Configure(testEnv env.Environment) { reuseCluster := CheckEnvVarExists(reuseClusterEnv) + log.V(4).Info("Reusing cluster: ", reuseCluster) kindClusterName := clusterName(reuseCluster) - + log.V(4).Info("Cluster name: ", kindClusterName) firstSetup := true if reuseCluster && clusterExists(kindClusterName) { firstSetup = false } + + log.V(4).Info("Is first setup: ", firstSetup) + // Setup uses pre-defined funcs to create kind cluster // and create a namespace for the environment testEnv.Setup( @@ -56,7 +61,7 @@ func (s *ClusterSetup) Run(testEnv env.Environment) { Name: s.Name, Package: s.Images.Package, ControllerImage: s.Images.ControllerImage, - ControllerConfig: &s.ControllerConfig, + ControllerConfig: s.ControllerConfig, }, ), firstSetup, ), @@ -78,10 +83,12 @@ func (s *ClusterSetup) Run(testEnv env.Environment) { func clusterName(reuseCluster bool) string { var kindClusterName string - if !reuseCluster && CheckEnvVarExists(clusterNameEnv) { - kindClusterName = envvar.GetOrDefault(clusterNameEnv, envconf.RandomName(defaultPrefix, 10)) - } else { + if CheckEnvVarExists(clusterNameEnv) { + kindClusterName = envvar.GetOrPanic(clusterNameEnv) + } else if reuseCluster { kindClusterName = defaultPrefix + } else { + kindClusterName = envvar.GetOrDefault(clusterNameEnv, envconf.RandomName(defaultPrefix, 10)) } return kindClusterName } From a63e1301871bb53ec8809f5cac22d326cc9e927e Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Mon, 14 Aug 2023 09:47:22 +0200 Subject: [PATCH 11/23] renaming env vars Signed-off-by: Maximilian Braun (SAP) --- go.mod | 2 -- pkg/images/lookup.go | 9 +++++---- pkg/images/lookup_test.go | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index c9d5d5a..c8067f1 100644 --- a/go.mod +++ b/go.mod @@ -92,7 +92,5 @@ require ( ) replace github.com/crossplane/crossplane => github.com/crossplane/crossplane v1.11.5 - replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.19.2 - replace github.com/docker/docker => github.com/docker/docker v1.4.2-0.20190219180918-740349757396 diff --git a/pkg/images/lookup.go b/pkg/images/lookup.go index 39193ac..545e8f5 100644 --- a/pkg/images/lookup.go +++ b/pkg/images/lookup.go @@ -2,6 +2,7 @@ package images import ( "encoding/json" + "fmt" "github.com/pkg/errors" @@ -9,7 +10,7 @@ import ( ) const ( - imagesJSONEnv = "TEST_IMAGES" + imagesJSONEnv = "E2E_IMAGES" ) // ProviderImages holds information to the docker images for providers @@ -18,8 +19,8 @@ type ProviderImages struct { ControllerImage *string } -// GetImagesFromJSONOrPanic retrieves image information from the environment and panics if `TEST_IMAGES` is not set -// `TEST_IMAGES` is expected to be a simple json like this. +// GetImagesFromJSONOrPanic retrieves image information from the environment and panics if `E2E_IMAGES` is not set +// `E2E_IMAGES` is expected to be a simple json like this. // ```{"$PackageKey": "ImageUrlOfPackageImage", "$controllerKey": "ImageUrlOfControllerImage"}``` // The controller image (key) is optional func GetImagesFromJSONOrPanic(packageKey string, controllerKey *string) ProviderImages { @@ -29,7 +30,7 @@ func GetImagesFromJSONOrPanic(packageKey string, controllerKey *string) Provider err := json.Unmarshal([]byte(imagesJSON), &images) if err != nil { - panic(errors.Wrap(err, "failed to unmarshal json from UUT_IMAGE")) + panic(errors.Wrap(err, fmt.Sprintf("failed to unmarshal json from %s", imagesJSONEnv))) } uutConfig := images[packageKey] diff --git a/pkg/images/lookup_test.go b/pkg/images/lookup_test.go index 08298d5..e899ee1 100644 --- a/pkg/images/lookup_test.go +++ b/pkg/images/lookup_test.go @@ -21,7 +21,7 @@ func (suite *LookupSuite) TestGetImagesFromJSONOrPanic() { controllerKey := "baz" suite.T().Run("Returns both images from environment", func(t *testing.T) { - err := os.Setenv("TEST_IMAGES", "{\"foo\": \"bar\", \"baz\": \"boom\"}") + err := os.Setenv("E2E_IMAGES", "{\"foo\": \"bar\", \"baz\": \"boom\"}") println(err) providerImages := GetImagesFromJSONOrPanic(packageKey, &controllerKey) assert.Equal(t, "bar", providerImages.Package) @@ -29,24 +29,24 @@ func (suite *LookupSuite) TestGetImagesFromJSONOrPanic() { }) suite.T().Run("Returns existing env vars", func(t *testing.T) { - os.Setenv("TEST_IMAGES", "{\"foo\": \"bar\"}") + os.Setenv("E2E_IMAGES", "{\"foo\": \"bar\"}") providerImages := GetImagesFromJSONOrPanic(packageKey, nil) assert.Equal(t, "bar", providerImages.Package) assert.Nil(t, providerImages.ControllerImage) }) suite.T().Run("env var not set, will panic", func(t *testing.T) { - os.Unsetenv("TEST_IMAGES") + os.Unsetenv("E2E_IMAGES") assert.Panics(t, func() { GetImagesFromJSONOrPanic(packageKey, nil) }) }) suite.T().Run("invalid json, will panic", func(t *testing.T) { - os.Setenv("TEST_IMAGES", "//invalid.json") + os.Setenv("E2E_IMAGES", "//invalid.json") assert.Panics(t, func() { GetImagesFromJSONOrPanic(packageKey, nil) }) }) - os.Unsetenv("TEST_IMAGES") + os.Unsetenv("E2E_IMAGES") } From 2a6937f5d0d3bded3ec55bb5559254fefb476102 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Mon, 14 Aug 2023 11:05:01 +0200 Subject: [PATCH 12/23] rename Signed-off-by: Maximilian Braun (SAP) --- pkg/images/lookup.go | 4 ++-- pkg/images/lookup_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/images/lookup.go b/pkg/images/lookup.go index 545e8f5..d4b9622 100644 --- a/pkg/images/lookup.go +++ b/pkg/images/lookup.go @@ -19,11 +19,11 @@ type ProviderImages struct { ControllerImage *string } -// GetImagesFromJSONOrPanic retrieves image information from the environment and panics if `E2E_IMAGES` is not set +// GetImagesFromEnvironmentOrPanic retrieves image information from the environment and panics if `E2E_IMAGES` is not set // `E2E_IMAGES` is expected to be a simple json like this. // ```{"$PackageKey": "ImageUrlOfPackageImage", "$controllerKey": "ImageUrlOfControllerImage"}``` // The controller image (key) is optional -func GetImagesFromJSONOrPanic(packageKey string, controllerKey *string) ProviderImages { +func GetImagesFromEnvironmentOrPanic(packageKey string, controllerKey *string) ProviderImages { imagesJSON := envvar.GetOrPanic(imagesJSONEnv) images := map[string]string{} diff --git a/pkg/images/lookup_test.go b/pkg/images/lookup_test.go index e899ee1..e3a3623 100644 --- a/pkg/images/lookup_test.go +++ b/pkg/images/lookup_test.go @@ -23,14 +23,14 @@ func (suite *LookupSuite) TestGetImagesFromJSONOrPanic() { suite.T().Run("Returns both images from environment", func(t *testing.T) { err := os.Setenv("E2E_IMAGES", "{\"foo\": \"bar\", \"baz\": \"boom\"}") println(err) - providerImages := GetImagesFromJSONOrPanic(packageKey, &controllerKey) + providerImages := GetImagesFromEnvironmentOrPanic(packageKey, &controllerKey) assert.Equal(t, "bar", providerImages.Package) assert.Equal(t, "boom", *providerImages.ControllerImage) }) suite.T().Run("Returns existing env vars", func(t *testing.T) { os.Setenv("E2E_IMAGES", "{\"foo\": \"bar\"}") - providerImages := GetImagesFromJSONOrPanic(packageKey, nil) + providerImages := GetImagesFromEnvironmentOrPanic(packageKey, nil) assert.Equal(t, "bar", providerImages.Package) assert.Nil(t, providerImages.ControllerImage) }) @@ -38,14 +38,14 @@ func (suite *LookupSuite) TestGetImagesFromJSONOrPanic() { suite.T().Run("env var not set, will panic", func(t *testing.T) { os.Unsetenv("E2E_IMAGES") assert.Panics(t, func() { - GetImagesFromJSONOrPanic(packageKey, nil) + GetImagesFromEnvironmentOrPanic(packageKey, nil) }) }) suite.T().Run("invalid json, will panic", func(t *testing.T) { os.Setenv("E2E_IMAGES", "//invalid.json") assert.Panics(t, func() { - GetImagesFromJSONOrPanic(packageKey, nil) + GetImagesFromEnvironmentOrPanic(packageKey, nil) }) }) os.Unsetenv("E2E_IMAGES") From fbd09470158e4ea8c6f6a384efe1b2f4318c5e36 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Mon, 14 Aug 2023 12:43:51 +0200 Subject: [PATCH 13/23] remove forceful namepsace create Signed-off-by: Maximilian Braun (SAP) --- pkg/setup/setup.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 79f7108..0c3fa1b 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -66,7 +66,6 @@ func (s *ClusterSetup) Configure(testEnv env.Environment) { ), firstSetup, ), xenvfuncs.ApplySecretInCrossplaneNamespace("secret", s.SecretData), - xenvfuncs.CreateTestNamespace, xenvfuncs.ApplyProviderConfig, xenvfuncs.LoadSchemas(s.AddToSchemaFuncs...), xenvfuncs.AwaitCRDsEstablished, From 11cec67bb2d981db4058af6270347207b49d81bf Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Mon, 14 Aug 2023 15:29:03 +0200 Subject: [PATCH 14/23] fix: initialization of conditions Signed-off-by: Maximilian Braun (SAP) --- pkg/conditions/conditions.go | 2 +- pkg/xenvfuncs/xenvfuncs.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/conditions/conditions.go b/pkg/conditions/conditions.go index 890de33..20f1738 100644 --- a/pkg/conditions/conditions.go +++ b/pkg/conditions/conditions.go @@ -21,7 +21,7 @@ type Conditions struct { // New is constructor for Conditions func New(r *resources.Resources) *Conditions { - return &Conditions{resources: r} + return &Conditions{Condition: *apimachineryconditions.New(r), resources: r} } // ManagedResourceConditionMatch checks if a ManagedResource has a matching condition diff --git a/pkg/xenvfuncs/xenvfuncs.go b/pkg/xenvfuncs/xenvfuncs.go index e487e40..0bcb377 100644 --- a/pkg/xenvfuncs/xenvfuncs.go +++ b/pkg/xenvfuncs/xenvfuncs.go @@ -448,8 +448,9 @@ func AwaitCRDsEstablished(ctx context.Context, cfg *envconf.Config) (context.Con return ctx, err } + c := conditions.New(client) err = wait.For( - conditions.New(client).ResourcesMatch(&crds, crdIsEstablished), wait.WithTimeout(time.Minute), + c.ResourcesMatch(&crds, crdIsEstablished), wait.WithTimeout(time.Minute), ) return ctx, err } From 283b92d2ef82af504c4be877b7fd573a7f653bf7 Mon Sep 17 00:00:00 2001 From: Maximilian Braun Date: Fri, 18 Aug 2023 09:52:05 +0200 Subject: [PATCH 15/23] refactor structure Signed-off-by: Maximilian Braun (SAP) --- go.mod | 10 +- go.sum | 28 +++-- pkg/conditions/conditions.go | 46 -------- pkg/resources/resources.go | 61 +++++----- pkg/setup/setup.go | 48 ++++---- pkg/xpconditions/xpconditions.go | 108 ++++++++++++++++++ pkg/xpconditions/xpconditions_test.go | 91 +++++++++++++++ .../xenvfuncs.go => xpenvfuncs/xpenvfuncs.go} | 33 ++++-- .../xpenvfuncs_test.go} | 24 +++- 9 files changed, 315 insertions(+), 134 deletions(-) delete mode 100644 pkg/conditions/conditions.go create mode 100644 pkg/xpconditions/xpconditions.go create mode 100644 pkg/xpconditions/xpconditions_test.go rename pkg/{xenvfuncs/xenvfuncs.go => xpenvfuncs/xpenvfuncs.go} (95%) rename pkg/{xenvfuncs/xenvfuncs_test.go => xpenvfuncs/xpenvfuncs_test.go} (92%) diff --git a/go.mod b/go.mod index c8067f1..f518141 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,10 @@ require ( github.com/samber/lo v1.38.1 github.com/stretchr/testify v1.8.4 github.com/vladimirvivien/gexe v0.2.0 - k8s.io/api v0.27.4 - k8s.io/apiextensions-apiserver v0.27.4 - k8s.io/apimachinery v0.27.4 - k8s.io/client-go v0.27.4 + k8s.io/api v0.26.3 + k8s.io/apiextensions-apiserver v0.26.1 + k8s.io/apimachinery v0.26.3 + k8s.io/client-go v0.26.3 k8s.io/klog/v2 v2.100.1 sigs.k8s.io/controller-runtime v0.14.6 sigs.k8s.io/e2e-framework v0.2.0 @@ -92,5 +92,7 @@ require ( ) replace github.com/crossplane/crossplane => github.com/crossplane/crossplane v1.11.5 + replace github.com/crossplane/crossplane-runtime => github.com/crossplane/crossplane-runtime v0.19.2 + replace github.com/docker/docker => github.com/docker/docker v1.4.2-0.20190219180918-740349757396 diff --git a/go.sum b/go.sum index 8a4400e..74ba5a6 100644 --- a/go.sum +++ b/go.sum @@ -118,6 +118,7 @@ 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/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -154,7 +155,6 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En 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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -227,7 +227,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf 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-20221102093814-76f304f74e5e h1:F1LLQqQ8WoIbyoxLUY+JUZe1kuHdxThM6CPUATzE6Io= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= @@ -278,8 +277,8 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 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= @@ -316,10 +315,10 @@ github.com/nightlyone/lockfile v0.0.0-20180618180623-0ad87eef1443/go.mod h1:Jbxf github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= +github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -355,7 +354,6 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= @@ -794,15 +792,15 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh 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.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= -k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= -k8s.io/apiextensions-apiserver v0.27.4 h1:ie1yZG4nY/wvFMIR2hXBeSVq+HfNzib60FjnBYtPGSs= -k8s.io/apiextensions-apiserver v0.27.4/go.mod h1:KHZaDr5H9IbGEnSskEUp/DsdXe1hMQ7uzpQcYUFt2bM= -k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= -k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= -k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= -k8s.io/component-base v0.27.4 h1:Wqc0jMKEDGjKXdae8hBXeskRP//vu1m6ypC+gwErj4c= +k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= +k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= +k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI= +k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM= +k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= +k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= +k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= +k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4= 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-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI= diff --git a/pkg/conditions/conditions.go b/pkg/conditions/conditions.go deleted file mode 100644 index 20f1738..0000000 --- a/pkg/conditions/conditions.go +++ /dev/null @@ -1,46 +0,0 @@ -package conditions - -import ( - "context" - - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" - pkgv1 "github.com/crossplane/crossplane/apis/pkg/v1" - corev1 "k8s.io/api/core/v1" - apimachinerywait "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog/v2" - "sigs.k8s.io/e2e-framework/klient/k8s" - "sigs.k8s.io/e2e-framework/klient/k8s/resources" - apimachineryconditions "sigs.k8s.io/e2e-framework/klient/wait/conditions" -) - -// Conditions helps with matching resources on conditions -type Conditions struct { - apimachineryconditions.Condition - resources *resources.Resources -} - -// New is constructor for Conditions -func New(r *resources.Resources) *Conditions { - return &Conditions{Condition: *apimachineryconditions.New(r), resources: r} -} - -// ManagedResourceConditionMatch checks if a ManagedResource has a matching condition -func (c *Conditions) ManagedResourceConditionMatch( - provider k8s.Object, - conditionType xpv1.ConditionType, - conditionState corev1.ConditionStatus, -) apimachinerywait.ConditionFunc { - return func() (done bool, err error) { - klog.V(4).Infof("Awaiting provider %s to be ready", provider.GetName()) - if err := c.resources.Get(context.TODO(), provider.GetName(), provider.GetNamespace(), provider); err != nil { - return false, err - } - for _, cond := range provider.(*pkgv1.Provider).Status.Conditions { - klog.V(4).Infof("provider %s, condition: %s: %s", provider.GetName(), cond.Type, cond.Status) - if cond.Type == conditionType && cond.Status == conditionState { - done = true - } - } - return - } -} diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index dbe8133..ad353a8 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -3,16 +3,15 @@ package resources import ( "context" "fmt" + "github.com/maximilianbraun/xp-testing/pkg/xpconditions" "os" + "path" "path/filepath" "testing" "time" - xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" - "github.com/crossplane/crossplane-runtime/pkg/resource" crossplanev1 "github.com/crossplane/crossplane/apis/pkg/v1" "github.com/samber/lo" - v1 "k8s.io/api/core/v1" v1extensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,7 +28,7 @@ import ( "sigs.k8s.io/e2e-framework/pkg/envconf" ) -// ImportResources gets the resources from ./data/crs +// ImportResources gets the resources from dir func ImportResources(ctx context.Context, t *testing.T, cfg *envconf.Config, dir string) { r := resClient(cfg) @@ -44,7 +43,7 @@ func ImportResources(ctx context.Context, t *testing.T, cfg *envconf.Config, dir // managed resources fare cluster scoped, so if we patched them with the test namespace it won't do anything errdecode := decoder.DecodeEachFile( - ctx, os.DirFS(filepath.Join("./data/crs", dir)), "*", + ctx, os.DirFS(dir), "*", decoder.CreateIgnoreAlreadyExists(r), ) if errdecode != nil { @@ -64,7 +63,7 @@ func GetResourcesWithRESTConfig(cfg *envconf.Config) (*resources.Resources, erro } func checkAtLeastOneYamlFile(dir string) (bool, error) { - files, err := filepath.Glob(filepath.Join("./data/crs", dir, "*.yaml")) + files, err := filepath.Glob(filepath.Join(dir, "*.yaml")) if err != nil { return false, err } @@ -89,7 +88,7 @@ func WaitForResourcesToBeSynced( res := cfg.Client().Resources() err = wait.For( - conditions.New(res).ResourcesMatch(&mockList{Items: objects}, managedResourceSyncedAndAvailable), opts..., + xpconditions.New(res).ManagedResourcesReadyAndReady(&mockList{Items: objects}), opts..., ) return err } @@ -113,22 +112,6 @@ func identifiers(objects []k8s.Object) string { return val } -func managedResourceSyncedAndAvailable(object k8s.Object) bool { - managed, ok := object.(resource.Managed) - if !ok { - klog.V(4).Infof("Object (%s) is not a managed resource, treat as synced", Identifier(object)) - return true - } - - return managedCheckCondition(managed, xpv1.TypeSynced, v1.ConditionTrue) && - managedCheckCondition(managed, xpv1.TypeReady, v1.ConditionTrue) -} - -func managedCheckCondition(o resource.Managed, conditionType xpv1.ConditionType, want v1.ConditionStatus) bool { - got := o.GetCondition(conditionType).Status - return want == got -} - func getObjectsToImport(ctx context.Context, cfg *envconf.Config, dir string) ([]k8s.Object, error) { r := resClient(cfg) @@ -136,7 +119,7 @@ func getObjectsToImport(ctx context.Context, cfg *envconf.Config, dir string) ([ objects := make([]k8s.Object, 0) err := decoder.DecodeEachFile( - ctx, os.DirFS(filepath.Join("./data/crs", dir)), "*", + ctx, os.DirFS(dir), "*", func(ctx context.Context, obj k8s.Object) error { objects = append(objects, obj) return nil @@ -261,15 +244,16 @@ func deleteObjects(ctx context.Context, cfg *envconf.Config, dir string) error { r.WithNamespace(cfg.Namespace()) return decoder.DecodeEachFile( - ctx, os.DirFS(filepath.Join("./data/crs", dir)), "*", + ctx, os.DirFS(dir), "*", decoder.DeleteHandler(r), ) } // AwaitResourceUpdateOrError waits for a given resource to update with a timeout of 3 minutes func AwaitResourceUpdateOrError(ctx context.Context, t *testing.T, cfg *envconf.Config, object k8s.Object) { + xpc := xpconditions.New(cfg.Client().Resources()) AwaitResourceUpdateFor( - ctx, t, cfg, object, managedResourceSyncedAndAvailable, + ctx, t, cfg, object, xpc.IsManagedResourceReadyAndReady, wait.WithTimeout(time.Minute*3), ) } @@ -320,15 +304,28 @@ func AwaitResourceDeletionOrFail(ctx context.Context, t *testing.T, cfg *envconf // It contains the kind of resource and the object to be tested // and then provides basic CRD tests for the resource. type ResourceTestConfig struct { - Kind string - Obj k8s.Object - AdditionalSteps map[string]func(context.Context, *testing.T, *envconf.Config) context.Context + Kind string + Obj k8s.Object + AdditionalSteps map[string]func(context.Context, *testing.T, *envconf.Config) context.Context + ResourceDirectory string +} + +func NewResourceTestConfig(obj k8s.Object, kind string) *ResourceTestConfig { + return &ResourceTestConfig{Kind: kind, Obj: obj, AdditionalSteps: nil, ResourceDirectory: DefaultCRFolder(kind)} + +} + +func (r *ResourceTestConfig) DefaultCRFolder() string { + return path.Join("./crs", r.Kind) +} +func DefaultCRFolder(kind string) string { + return path.Join("./crs", kind) } // Setup creates the resource in the cluster. func (r *ResourceTestConfig) Setup(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { t.Logf("Apply %s", r.Kind) - ImportResources(ctx, t, cfg, r.Kind) + ImportResources(ctx, t, cfg, r.ResourceDirectory) return ctx } @@ -340,7 +337,7 @@ func (r *ResourceTestConfig) Teardown(ctx context.Context, t *testing.T, cfg *en // AssessCreate checks that the resource was created successfully. func (r *ResourceTestConfig) AssessCreate(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { - if err := WaitForResourcesToBeSynced(ctx, cfg, r.Kind, wait.WithTimeout(time.Minute*5)); err != nil { + if err := WaitForResourcesToBeSynced(ctx, cfg, r.ResourceDirectory, wait.WithTimeout(time.Minute*5)); err != nil { DumpManagedResources(ctx, t, cfg) t.Fatal(err) } @@ -354,5 +351,5 @@ func (r *ResourceTestConfig) AssessUpdate(ctx context.Context, t *testing.T, cfg // AssessDelete checks that the resource was deleted successfully. func (r *ResourceTestConfig) AssessDelete(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { - return DeleteResources(ctx, t, cfg, r.Kind, wait.WithTimeout(time.Minute*5)) + return DeleteResources(ctx, t, cfg, r.ResourceDirectory, wait.WithTimeout(time.Minute*5)) } diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 0c3fa1b..7611bb6 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -14,7 +14,7 @@ import ( "github.com/maximilianbraun/xp-testing/pkg/envvar" "github.com/maximilianbraun/xp-testing/pkg/images" - "github.com/maximilianbraun/xp-testing/pkg/xenvfuncs" + "github.com/maximilianbraun/xp-testing/pkg/xpenvfuncs" ) const ( @@ -25,11 +25,12 @@ const ( // ClusterSetup help with a default kind setup for crossplane, with crossplane and a provider type ClusterSetup struct { - Name string - Images images.ProviderImages - ControllerConfig *v1alpha1.ControllerConfig - SecretData map[string]string - AddToSchemaFuncs []func(s *runtime.Scheme) error + Name string + Images images.ProviderImages + ControllerConfig *v1alpha1.ControllerConfig + SecretData map[string]string + AddToSchemaFuncs []func(s *runtime.Scheme) error + CrossplaneVersion string } // Configure optionally creates the kind cluster and takes care about the rest of the setup, @@ -54,29 +55,28 @@ func (s *ClusterSetup) Configure(testEnv env.Environment) { // and create a namespace for the environment testEnv.Setup( envfuncs.CreateKindCluster(kindClusterName), - xenvfuncs.Conditional(xenvfuncs.InstallCrossplane(kindClusterName), firstSetup), - xenvfuncs.Conditional( - xenvfuncs.InstallCrossplaneProvider( - kindClusterName, xenvfuncs.InstallCrossplaneProviderOptions{ - Name: s.Name, - Package: s.Images.Package, - ControllerImage: s.Images.ControllerImage, - ControllerConfig: s.ControllerConfig, - }, - ), firstSetup, - ), - xenvfuncs.ApplySecretInCrossplaneNamespace("secret", s.SecretData), - xenvfuncs.ApplyProviderConfig, - xenvfuncs.LoadSchemas(s.AddToSchemaFuncs...), - xenvfuncs.AwaitCRDsEstablished, + xpenvfuncs.Conditional( + xpenvfuncs.Compose( + xpenvfuncs.InstallCrossplane(kindClusterName, s.CrossplaneVersion), + xpenvfuncs.InstallCrossplaneProvider( + kindClusterName, xpenvfuncs.InstallCrossplaneProviderOptions{ + Name: s.Name, + Package: s.Images.Package, + ControllerImage: s.Images.ControllerImage, + ControllerConfig: s.ControllerConfig, + }), + xpenvfuncs.ApplySecretInCrossplaneNamespace("secret", s.SecretData), + ), firstSetup), + xpenvfuncs.ApplyProviderConfig, + xpenvfuncs.LoadSchemas(s.AddToSchemaFuncs...), + xpenvfuncs.AwaitCRDsEstablished, ) // Finish uses pre-defined funcs to // remove namespace, then delete cluster testEnv.Finish( - xenvfuncs.DumpKindLogs(kindClusterName), - xenvfuncs.DeleteTestNamespace, - xenvfuncs.Conditional(envfuncs.DestroyKindCluster(kindClusterName), !reuseCluster), + xpenvfuncs.DumpKindLogs(kindClusterName), + xpenvfuncs.Conditional(envfuncs.DestroyKindCluster(kindClusterName), !reuseCluster), ) } diff --git a/pkg/xpconditions/xpconditions.go b/pkg/xpconditions/xpconditions.go new file mode 100644 index 0000000..568e0c3 --- /dev/null +++ b/pkg/xpconditions/xpconditions.go @@ -0,0 +1,108 @@ +package xpconditions + +import ( + "context" + "encoding/json" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/resource" + pkgv1 "github.com/crossplane/crossplane/apis/pkg/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + apimachinerywait "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/klog/v2" + "sigs.k8s.io/e2e-framework/klient/k8s" + "sigs.k8s.io/e2e-framework/klient/k8s/resources" + apimachineryconditions "sigs.k8s.io/e2e-framework/klient/wait/conditions" +) + +// Conditions helps with matching resources on conditions +type Conditions struct { + apimachineryconditions.Condition + resources *resources.Resources +} + +// New is constructor for Conditions +func New(r *resources.Resources) *Conditions { + return &Conditions{Condition: *apimachineryconditions.New(r), resources: r} +} + +// ProviderConditionMatch checks if a Provider has a matching condition +func (c *Conditions) ProviderConditionMatch( + provider k8s.Object, + conditionType xpv1.ConditionType, + conditionStatus corev1.ConditionStatus, +) apimachinerywait.ConditionFunc { + return func() (done bool, err error) { + klog.V(4).Infof("Awaiting provider %s to be ready", provider.GetName()) + if err := c.resources.Get(context.TODO(), provider.GetName(), provider.GetNamespace(), provider); err != nil { + return false, err + } + for _, cond := range provider.(*pkgv1.Provider).Status.Conditions { + klog.V(4).Infof("provider %s, condition: %s: %s", provider.GetName(), cond.Type, cond.Status) + if cond.Type == conditionType && cond.Status == conditionStatus { + done = true + } + } + return + } +} + +func (c *Conditions) IsManagedResourceReadyAndReady(object k8s.Object) bool { + + managed := convertToManaged(object) + return managedCheckCondition(managed, xpv1.TypeSynced, corev1.ConditionTrue) && + managedCheckCondition(managed, xpv1.TypeReady, corev1.ConditionTrue) +} + +func convertToManaged(object k8s.Object) resource.Managed { + unstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(object) + if err != nil { + return nil + } + var managed DummyManaged + err = runtime.DefaultUnstructuredConverter. + FromUnstructured(unstructured, &managed) + + if err != nil { + panic(err) + } + + return &managed +} + +// ManagedResourcesReadyAndReady checks if a list of ManagedResources has a matching condition +func (c *Conditions) ManagedResourcesReadyAndReady( + list k8s.ObjectList, +) apimachinerywait.ConditionFunc { + return c.Condition.ResourcesMatch(list, c.IsManagedResourceReadyAndReady) +} + +func managedCheckCondition(o resource.Managed, conditionType xpv1.ConditionType, want corev1.ConditionStatus) bool { + klog.V(4).Infof("Checking Managed Resource %s to be condition: %s: %s", o.GetName(), conditionType, want) + got := o.GetCondition(conditionType) + klog.V(4).Infof("Got Managed Resource %s to be condition: %s: %s, message: %s", o.GetName(), conditionType, got.Status, got.Message) + return want == got.Status +} + +type DummyManaged struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + resource.ProviderReferencer + resource.ProviderConfigReferencer + resource.ConnectionSecretWriterTo + resource.ConnectionDetailsPublisherTo + resource.Orphanable + xpv1.ConditionedStatus `json:"status"` +} + +// DeepCopyObject returns a copy of the object as runtime.Object +func (m *DummyManaged) DeepCopyObject() runtime.Object { + out := &DummyManaged{} + j, err := json.Marshal(m) + if err != nil { + panic(err) + } + _ = json.Unmarshal(j, out) + return out +} diff --git a/pkg/xpconditions/xpconditions_test.go b/pkg/xpconditions/xpconditions_test.go new file mode 100644 index 0000000..b939860 --- /dev/null +++ b/pkg/xpconditions/xpconditions_test.go @@ -0,0 +1,91 @@ +package xpconditions + +import ( + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/e2e-framework/klient/k8s" + "testing" +) + +func Test_convertToManaged(t *testing.T) { + type args struct { + object k8s.Object + } + tests := []struct { + name string + args args + want resource.Managed + }{ + { + name: "happy path", + args: args{ + object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "foo.crossplane.io/v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "example-resource", + }, + // Should be ignored + "spec": map[string]interface{}{ + "forProvider": map[string]interface{}{ + "propertyKey": "value", + }, + }, + "status": map[string]interface{}{ + "atProvider": map[string]interface{}{ + "providerState": true, + }, + "conditions": []interface{}{ + map[string]interface{}{ + "reason": "Available", + "status": "True", + "type": "Ready", + }, + map[string]interface{}{ + "reason": "ReconcileSuccess", + "status": "True", + "type": "Synced", + }, + }, + }, + }, + }, + }, + want: &DummyManaged{ + TypeMeta: metav1.TypeMeta{ + Kind: "Foo", + APIVersion: "foo.crossplane.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "example-resource", + }, + ConditionedStatus: xpv1.ConditionedStatus{ + Conditions: []xpv1.Condition{ + { + Type: xpv1.TypeReady, + Status: corev1.ConditionTrue, + Reason: xpv1.ReasonAvailable, + }, + { + Type: xpv1.TypeSynced, + Status: corev1.ConditionTrue, + Reason: xpv1.ReasonReconcileSuccess, + }, + }, + }, + }}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := convertToManaged(tt.args.object) + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("convertToManaged() = %v, want %v, diff: %v", got, tt.want, diff) + } + }) + } +} diff --git a/pkg/xenvfuncs/xenvfuncs.go b/pkg/xpenvfuncs/xpenvfuncs.go similarity index 95% rename from pkg/xenvfuncs/xenvfuncs.go rename to pkg/xpenvfuncs/xpenvfuncs.go index 0bcb377..0c73818 100644 --- a/pkg/xenvfuncs/xenvfuncs.go +++ b/pkg/xpenvfuncs/xpenvfuncs.go @@ -1,4 +1,4 @@ -package xenvfuncs +package xpenvfuncs import ( "bytes" @@ -30,12 +30,12 @@ import ( "sigs.k8s.io/e2e-framework/third_party/helm" "sigs.k8s.io/kind/pkg/cluster" - xconditions "github.com/maximilianbraun/xp-testing/pkg/conditions" resHelper "github.com/maximilianbraun/xp-testing/pkg/resources" + xconditions "github.com/maximilianbraun/xp-testing/pkg/xpconditions" "github.com/maximilianbraun/xp-testing/internal/docker" "github.com/maximilianbraun/xp-testing/internal/xpkg" - "github.com/maximilianbraun/xp-testing/pkg/conditions" + "github.com/maximilianbraun/xp-testing/pkg/xpconditions" ) const crsCrossplaneCacheVolumeTemplate = `apiVersion: v1 @@ -94,7 +94,7 @@ var ( type clusterNameType string // InstallCrossplane returns an env.Func that is used to install crossplane into the given cluster -func InstallCrossplane(clusterName string) env.Func { // TODO specify version +func InstallCrossplane(clusterName string, crossplaneVersion string) env.Func { cacheName := "package-cache" return Compose( @@ -124,14 +124,13 @@ func InstallCrossplane(clusterName string) env.Func { // TODO specify version helmInstallOpts := []helm.Option{ helm.WithName("crossplane"), helm.WithNamespace("crossplane-system"), + helm.WithVersion(crossplaneVersion), helm.WithReleaseName(helmRepoName + "/crossplane"), helm.WithArgs("--set", fmt.Sprintf("packageCache.pvc=%s", cacheName)), - helm.WithWait(), helm.WithTimeout("10m"), + helm.WithWait(), } - // TODO set target crossplane version - if err := manager.RunInstall(helmInstallOpts...); err != nil { return ctx, errors.Wrap(err, "install crossplane func: failed to install crossplane Helm chart") } @@ -189,13 +188,13 @@ func ApplyProviderConfig(ctx context.Context, cfg *envconf.Config) (context.Cont klog.Info("Apply ProviderConfig") errDecode := decoder.DecodeEachFile( - ctx, os.DirFS("./data/provider"), "*", + ctx, os.DirFS("./provider"), "*", decoder.CreateHandler(r), decoder.MutateNamespace(cfg.Namespace()), ) if errDecode != nil { - klog.Error("Error Details", "errDecode", errDecode) + klog.Error("Error Details ", "errDecode ", errDecode) } return ctx, nil @@ -345,7 +344,7 @@ func awaitProviderHealthy(opts InstallCrossplaneProviderOptions) env.Func { return ctx, err } err = wait.For( - xconditions.New(r).ManagedResourceConditionMatch( + xconditions.New(r).ProviderConditionMatch( &provider, pkgv1.TypeHealthy, corev1.ConditionTrue, @@ -405,7 +404,17 @@ func renderTemplate(tmpl string, data interface{}) (string, error) { func IgnoreErr(fn env.Func) env.Func { return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { if _, err := fn(ctx, cfg); err != nil { - klog.V(4).Info(err) + klog.V(4).Info("Ignored Err:", err) + } + return ctx, nil + } + +} + +func IgnoreMatchedErr(fn env.Func, errorMatcher func(err error) bool) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + if _, err := fn(ctx, cfg); err != nil && errorMatcher(err) { + klog.V(4).Info("Ignored Err:", err) } return ctx, nil } @@ -448,7 +457,7 @@ func AwaitCRDsEstablished(ctx context.Context, cfg *envconf.Config) (context.Con return ctx, err } - c := conditions.New(client) + c := xpconditions.New(client) err = wait.For( c.ResourcesMatch(&crds, crdIsEstablished), wait.WithTimeout(time.Minute), ) diff --git a/pkg/xenvfuncs/xenvfuncs_test.go b/pkg/xpenvfuncs/xpenvfuncs_test.go similarity index 92% rename from pkg/xenvfuncs/xenvfuncs_test.go rename to pkg/xpenvfuncs/xpenvfuncs_test.go index 27a8804..d3e2d5b 100644 --- a/pkg/xenvfuncs/xenvfuncs_test.go +++ b/pkg/xpenvfuncs/xpenvfuncs_test.go @@ -1,4 +1,4 @@ -package xenvfuncs +package xpenvfuncs import ( "context" @@ -292,3 +292,25 @@ func TestIgnoreErr(t *testing.T) { }, ) } + +func TestIgnoreMatchedErr(t *testing.T) { + t.Run( + "no error thown", func(t *testing.T) { + conditionalFn := IgnoreMatchedErr(dummyErrFunc, func(err error) bool { + return false + }) + _, err := conditionalFn(nil, nil) + assert.NoError(t, err) + }, + ) + + t.Run( + "error thown", func(t *testing.T) { + conditionalFn := IgnoreMatchedErr(dummyErrFunc, func(err error) bool { + return true + }) + _, err := conditionalFn(nil, nil) + assert.NoError(t, err) + }, + ) +} From 2fea549a7d36a96161ddb930d399b54599f48dd9 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 18 Aug 2023 12:23:31 +0200 Subject: [PATCH 16/23] linting Signed-off-by: Maximilian Braun (SAP) --- .github/workflows/codeql.yml | 2 +- pkg/envvar/envvar.go | 6 +++ pkg/resources/resources.go | 9 +++- pkg/setup/setup.go | 28 +++++----- pkg/setup/setup_test.go | 78 +++++++++++++++++++++++++++ pkg/xpconditions/xpconditions.go | 3 ++ pkg/xpconditions/xpconditions_test.go | 3 +- pkg/xpenvfuncs/xpenvfuncs.go | 1 + 8 files changed, 110 insertions(+), 20 deletions(-) create mode 100644 pkg/setup/setup_test.go diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 20f9045..3f765f2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -8,7 +8,7 @@ on: branches: - main - release-* - workflow_dispatch: {} + workflow_dispatch: { } schedule: - cron: '27 2 * * 0' diff --git a/pkg/envvar/envvar.go b/pkg/envvar/envvar.go index 5f1ff9d..d6f052f 100644 --- a/pkg/envvar/envvar.go +++ b/pkg/envvar/envvar.go @@ -31,3 +31,9 @@ func getOrDefault(key string, defaultFn func(string) string) string { return defaultFn(key) } + +// CheckEnvVarExists returns if a environment variable exists +func CheckEnvVarExists(existsKey string) bool { + _, found := os.LookupEnv(existsKey) + return found +} diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index ad353a8..215057b 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -3,13 +3,14 @@ package resources import ( "context" "fmt" - "github.com/maximilianbraun/xp-testing/pkg/xpconditions" "os" "path" "path/filepath" "testing" "time" + "github.com/maximilianbraun/xp-testing/pkg/xpconditions" + crossplanev1 "github.com/crossplane/crossplane/apis/pkg/v1" "github.com/samber/lo" v1extensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -310,14 +311,18 @@ type ResourceTestConfig struct { ResourceDirectory string } +// NewResourceTestConfig constructs a simple version of ResourceTestConfig func NewResourceTestConfig(obj k8s.Object, kind string) *ResourceTestConfig { return &ResourceTestConfig{Kind: kind, Obj: obj, AdditionalSteps: nil, ResourceDirectory: DefaultCRFolder(kind)} } +// DefaultCRFolder returns a relative path to a folder where CR's for tests are suspected func (r *ResourceTestConfig) DefaultCRFolder() string { - return path.Join("./crs", r.Kind) + return DefaultCRFolder(r.Kind) } + +// DefaultCRFolder returns a relative path to a folder where CR's for tests are suspected func DefaultCRFolder(kind string) string { return path.Join("./crs", kind) } diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index 7611bb6..6e35d44 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -4,6 +4,8 @@ import ( "os" "strings" + "github.com/maximilianbraun/xp-testing/pkg/envvar" + "github.com/crossplane/crossplane/apis/pkg/v1alpha1" "github.com/vladimirvivien/gexe" "k8s.io/apimachinery/pkg/runtime" @@ -12,7 +14,6 @@ import ( "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" - "github.com/maximilianbraun/xp-testing/pkg/envvar" "github.com/maximilianbraun/xp-testing/pkg/images" "github.com/maximilianbraun/xp-testing/pkg/xpenvfuncs" ) @@ -40,7 +41,7 @@ type ClusterSetup struct { // * TESTCLUSTER_NAME: overwrites the cluster name func (s *ClusterSetup) Configure(testEnv env.Environment) { - reuseCluster := CheckEnvVarExists(reuseClusterEnv) + reuseCluster := envvar.CheckEnvVarExists(reuseClusterEnv) log.V(4).Info("Reusing cluster: ", reuseCluster) kindClusterName := clusterName(reuseCluster) log.V(4).Info("Cluster name: ", kindClusterName) @@ -81,15 +82,16 @@ func (s *ClusterSetup) Configure(testEnv env.Environment) { } func clusterName(reuseCluster bool) string { - var kindClusterName string - if CheckEnvVarExists(clusterNameEnv) { - kindClusterName = envvar.GetOrPanic(clusterNameEnv) - } else if reuseCluster { - kindClusterName = defaultPrefix - } else { - kindClusterName = envvar.GetOrDefault(clusterNameEnv, envconf.RandomName(defaultPrefix, 10)) + + if envvar.CheckEnvVarExists(clusterNameEnv) { + return os.Getenv(clusterNameEnv) } - return kindClusterName + + if reuseCluster { + return defaultPrefix + } + + return envconf.RandomName(defaultPrefix, 10) } // TODO: Maybe part of the k8s-e2e framework? @@ -103,9 +105,3 @@ func clusterExists(name string) bool { } return false } - -// CheckEnvVarExists returns if a environment variable exists -func CheckEnvVarExists(existsKey string) bool { - _, found := os.LookupEnv(existsKey) - return found -} diff --git a/pkg/setup/setup_test.go b/pkg/setup/setup_test.go new file mode 100644 index 0000000..e4de14a --- /dev/null +++ b/pkg/setup/setup_test.go @@ -0,0 +1,78 @@ +package setup + +import ( + "fmt" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +var someName = "Bar" + +func Test_clusterName(t *testing.T) { + type args struct { + reuseCluster bool + clusterNameEnvValue *string + } + tests := []struct { + name string + args args + matcher func(string) bool + }{ + { + name: "No reuse, no env var; returns default prefix with random suffix", + args: args{ + reuseCluster: false, + clusterNameEnvValue: nil, + }, + matcher: func(s string) bool { + prefix := fmt.Sprintf("%s-", defaultPrefix) + return strings.HasPrefix(s, prefix) + }, + }, + { + name: "reuse, no env var; returns default prefix", + args: args{ + reuseCluster: true, + clusterNameEnvValue: nil, + }, + matcher: func(s string) bool { + return s == defaultPrefix + }, + }, + { + name: "reuse, with env var; returns from env", + args: args{ + reuseCluster: true, + clusterNameEnvValue: &someName, + }, + matcher: func(s string) bool { + return s == someName + }, + }, + { + name: "no reuse, with env var; returns from env", + args: args{ + reuseCluster: false, + clusterNameEnvValue: &someName, + }, + matcher: func(s string) bool { + return s == someName + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.args.clusterNameEnvValue == nil { + assert.NoError(t, os.Unsetenv(clusterNameEnv)) + } else { + assert.NoError(t, os.Setenv(clusterNameEnv, *tt.args.clusterNameEnvValue)) + } + if got := clusterName(tt.args.reuseCluster); !tt.matcher(got) { + t.Errorf("clusterName() = %v; matcher returned error", got) + } + }) + } +} diff --git a/pkg/xpconditions/xpconditions.go b/pkg/xpconditions/xpconditions.go index 568e0c3..6fcc6df 100644 --- a/pkg/xpconditions/xpconditions.go +++ b/pkg/xpconditions/xpconditions.go @@ -3,6 +3,7 @@ package xpconditions import ( "context" "encoding/json" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/resource" pkgv1 "github.com/crossplane/crossplane/apis/pkg/v1" @@ -48,6 +49,7 @@ func (c *Conditions) ProviderConditionMatch( } } +// IsManagedResourceReadyAndReady returns if a managed resource has condtions Synced = True and Ready = True func (c *Conditions) IsManagedResourceReadyAndReady(object k8s.Object) bool { managed := convertToManaged(object) @@ -85,6 +87,7 @@ func managedCheckCondition(o resource.Managed, conditionType xpv1.ConditionType, return want == got.Status } +// DummyManaged acts as a fake / dummy to allow generic checks on any managed resource type DummyManaged struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` diff --git a/pkg/xpconditions/xpconditions_test.go b/pkg/xpconditions/xpconditions_test.go index b939860..bbb22f6 100644 --- a/pkg/xpconditions/xpconditions_test.go +++ b/pkg/xpconditions/xpconditions_test.go @@ -1,6 +1,8 @@ package xpconditions import ( + "testing" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/resource" "github.com/google/go-cmp/cmp" @@ -8,7 +10,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/e2e-framework/klient/k8s" - "testing" ) func Test_convertToManaged(t *testing.T) { diff --git a/pkg/xpenvfuncs/xpenvfuncs.go b/pkg/xpenvfuncs/xpenvfuncs.go index 0c73818..bd82b2e 100644 --- a/pkg/xpenvfuncs/xpenvfuncs.go +++ b/pkg/xpenvfuncs/xpenvfuncs.go @@ -411,6 +411,7 @@ func IgnoreErr(fn env.Func) env.Func { } +// IgnoreMatchedErr checks if a result of fn() returns an error and if the error matches result of errorMatcher() ignores the error to continue with execution func IgnoreMatchedErr(fn env.Func, errorMatcher func(err error) bool) env.Func { return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { if _, err := fn(ctx, cfg); err != nil && errorMatcher(err) { From 7ee662ac93b703130da1d7f6ad2411213c9b3069 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Tue, 24 Oct 2023 08:21:33 +0200 Subject: [PATCH 17/23] chore: README.md Signed-off-by: Maximilian Braun (SAP) --- README.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/README.md b/README.md index 975fcce..5c9beff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD # xp-testing ======= # xp-testiing @@ -7,3 +8,71 @@ ======= # xp-testing >>>>>>> 478ccae (Update README.md) +======= +# End-to-end test framework for Crossplane providers + + `xp-testing` is a library enabling end-to-end tests for Crossplane providers, based on + [kubernetes-sigs/e2e-framework](https://github.com/kubernetes-sigs/e2e-framework/). + +The testing framework helps to setup test suits, by handling the deployments of crossplane and providers & ensures +providers are loaded into the cluster & helpers to speedup test development. + +* `pkg/xpconditions` supports with assertions. +* `pkg/resources` helps with handling of importing and deleting of resources while testing & an opinonated way to + create Test Features. +* `pkg/setup` provides a default cluster setup, ready to take just the most necessary information and boostrap the + test suit +* `pkg/xpenvfuncs` provide basic functions to compose a test environment + + +## Getting Started and Documentation + +For getting started guides, installation, deployment, and administration, check latest +Crossplane [document](https://crossplane.io/docs/latest). + +A reference implementation of `xp-testing` is available in [provider-argocd](https://github.com/crossplane-contrib/provider-argocd/pull/89/files) + +## Contributing + +xp-testing is a community driven project and we welcome contributions. See the +Crossplane +[Contributing](https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md) +guidelines to get started. + +## Report a Bug + +For filing bugs, suggesting improvements, or requesting new features, please +open an [issue](https://github.com/crossplane-contrib/xp-testing/issues). + +## Contact + +Please use the following to reach members of the community: + +* Slack: Join our [slack channel](https://slack.crossplane.io) +* Forums: + [crossplane-dev](https://groups.google.com/forum/#!forum/crossplane-dev) +* Twitter: [@crossplane_io](https://twitter.com/crossplane_io) +* Email: [info@crossplane.io](mailto:info@crossplane.io) + +## Governance and Owners + +`xp-testing` is run according to the same +[Governance](https://github.com/crossplane/crossplane/blob/master/GOVERNANCE.md) +and [Ownership](https://github.com/crossplane/crossplane/blob/master/OWNERS.md) +structure as the core Crossplane project. + +## Code of Conduct + +`xp-testing` adheres to the same [Code of +Conduct](https://github.com/crossplane/crossplane/blob/master/CODE_OF_CONDUCT.md) +as the core Crossplane project. + +## Licensing + +xp-testing is under the Apache 2.0 license. + +## Credits + +Initially developed by [v0lkc](https://github.com/v0lkc), [mirzakopic](https://github.com/mirzakopic) and their team +at [SAP](https://github.com/SAP/). +>>>>>>> 1387da7 (chore: README.md) From 4a6b94b06989b3e1c4ad85bde83f80f70dbd3063 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 20 Oct 2023 16:48:34 +0200 Subject: [PATCH 18/23] prepare move Signed-off-by: Maximilian Braun (SAP) --- .editorconfig => move/.editorconfig | 0 {.github => move/.github}/workflows/codeql.yml | 0 {.github => move/.github}/workflows/lint.yaml | 0 .gitignore => move/.gitignore | 0 .golangci.yml => move/.golangci.yml | 0 DCO => move/DCO | 0 LICENSE => move/LICENSE | 0 README.md => move/README.md | 0 go.mod => move/go.mod | 0 go.sum => move/go.sum | 0 {internal => move/internal}/docker/docker.go | 0 {internal => move/internal}/docker/docker_test.go | 0 {internal => move/internal}/xpkg/xpkg.go | 0 {internal => move/internal}/xpkg/xpkg_test.go | 0 {pkg => move/pkg}/envvar/envvar.go | 0 {pkg => move/pkg}/envvar/envvar_test.go | 0 {pkg => move/pkg}/images/lookup.go | 0 {pkg => move/pkg}/images/lookup_test.go | 0 {pkg => move/pkg}/logging/logging.go | 0 {pkg => move/pkg}/logging/logging_test.go | 0 {pkg => move/pkg}/resources/resources.go | 0 {pkg => move/pkg}/setup/setup.go | 0 {pkg => move/pkg}/setup/setup_test.go | 0 {pkg => move/pkg}/xpconditions/xpconditions.go | 0 {pkg => move/pkg}/xpconditions/xpconditions_test.go | 0 {pkg => move/pkg}/xpenvfuncs/xpenvfuncs.go | 0 {pkg => move/pkg}/xpenvfuncs/xpenvfuncs_test.go | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename .editorconfig => move/.editorconfig (100%) rename {.github => move/.github}/workflows/codeql.yml (100%) rename {.github => move/.github}/workflows/lint.yaml (100%) rename .gitignore => move/.gitignore (100%) rename .golangci.yml => move/.golangci.yml (100%) rename DCO => move/DCO (100%) rename LICENSE => move/LICENSE (100%) rename README.md => move/README.md (100%) rename go.mod => move/go.mod (100%) rename go.sum => move/go.sum (100%) rename {internal => move/internal}/docker/docker.go (100%) rename {internal => move/internal}/docker/docker_test.go (100%) rename {internal => move/internal}/xpkg/xpkg.go (100%) rename {internal => move/internal}/xpkg/xpkg_test.go (100%) rename {pkg => move/pkg}/envvar/envvar.go (100%) rename {pkg => move/pkg}/envvar/envvar_test.go (100%) rename {pkg => move/pkg}/images/lookup.go (100%) rename {pkg => move/pkg}/images/lookup_test.go (100%) rename {pkg => move/pkg}/logging/logging.go (100%) rename {pkg => move/pkg}/logging/logging_test.go (100%) rename {pkg => move/pkg}/resources/resources.go (100%) rename {pkg => move/pkg}/setup/setup.go (100%) rename {pkg => move/pkg}/setup/setup_test.go (100%) rename {pkg => move/pkg}/xpconditions/xpconditions.go (100%) rename {pkg => move/pkg}/xpconditions/xpconditions_test.go (100%) rename {pkg => move/pkg}/xpenvfuncs/xpenvfuncs.go (100%) rename {pkg => move/pkg}/xpenvfuncs/xpenvfuncs_test.go (100%) diff --git a/.editorconfig b/move/.editorconfig similarity index 100% rename from .editorconfig rename to move/.editorconfig diff --git a/.github/workflows/codeql.yml b/move/.github/workflows/codeql.yml similarity index 100% rename from .github/workflows/codeql.yml rename to move/.github/workflows/codeql.yml diff --git a/.github/workflows/lint.yaml b/move/.github/workflows/lint.yaml similarity index 100% rename from .github/workflows/lint.yaml rename to move/.github/workflows/lint.yaml diff --git a/.gitignore b/move/.gitignore similarity index 100% rename from .gitignore rename to move/.gitignore diff --git a/.golangci.yml b/move/.golangci.yml similarity index 100% rename from .golangci.yml rename to move/.golangci.yml diff --git a/DCO b/move/DCO similarity index 100% rename from DCO rename to move/DCO diff --git a/LICENSE b/move/LICENSE similarity index 100% rename from LICENSE rename to move/LICENSE diff --git a/README.md b/move/README.md similarity index 100% rename from README.md rename to move/README.md diff --git a/go.mod b/move/go.mod similarity index 100% rename from go.mod rename to move/go.mod diff --git a/go.sum b/move/go.sum similarity index 100% rename from go.sum rename to move/go.sum diff --git a/internal/docker/docker.go b/move/internal/docker/docker.go similarity index 100% rename from internal/docker/docker.go rename to move/internal/docker/docker.go diff --git a/internal/docker/docker_test.go b/move/internal/docker/docker_test.go similarity index 100% rename from internal/docker/docker_test.go rename to move/internal/docker/docker_test.go diff --git a/internal/xpkg/xpkg.go b/move/internal/xpkg/xpkg.go similarity index 100% rename from internal/xpkg/xpkg.go rename to move/internal/xpkg/xpkg.go diff --git a/internal/xpkg/xpkg_test.go b/move/internal/xpkg/xpkg_test.go similarity index 100% rename from internal/xpkg/xpkg_test.go rename to move/internal/xpkg/xpkg_test.go diff --git a/pkg/envvar/envvar.go b/move/pkg/envvar/envvar.go similarity index 100% rename from pkg/envvar/envvar.go rename to move/pkg/envvar/envvar.go diff --git a/pkg/envvar/envvar_test.go b/move/pkg/envvar/envvar_test.go similarity index 100% rename from pkg/envvar/envvar_test.go rename to move/pkg/envvar/envvar_test.go diff --git a/pkg/images/lookup.go b/move/pkg/images/lookup.go similarity index 100% rename from pkg/images/lookup.go rename to move/pkg/images/lookup.go diff --git a/pkg/images/lookup_test.go b/move/pkg/images/lookup_test.go similarity index 100% rename from pkg/images/lookup_test.go rename to move/pkg/images/lookup_test.go diff --git a/pkg/logging/logging.go b/move/pkg/logging/logging.go similarity index 100% rename from pkg/logging/logging.go rename to move/pkg/logging/logging.go diff --git a/pkg/logging/logging_test.go b/move/pkg/logging/logging_test.go similarity index 100% rename from pkg/logging/logging_test.go rename to move/pkg/logging/logging_test.go diff --git a/pkg/resources/resources.go b/move/pkg/resources/resources.go similarity index 100% rename from pkg/resources/resources.go rename to move/pkg/resources/resources.go diff --git a/pkg/setup/setup.go b/move/pkg/setup/setup.go similarity index 100% rename from pkg/setup/setup.go rename to move/pkg/setup/setup.go diff --git a/pkg/setup/setup_test.go b/move/pkg/setup/setup_test.go similarity index 100% rename from pkg/setup/setup_test.go rename to move/pkg/setup/setup_test.go diff --git a/pkg/xpconditions/xpconditions.go b/move/pkg/xpconditions/xpconditions.go similarity index 100% rename from pkg/xpconditions/xpconditions.go rename to move/pkg/xpconditions/xpconditions.go diff --git a/pkg/xpconditions/xpconditions_test.go b/move/pkg/xpconditions/xpconditions_test.go similarity index 100% rename from pkg/xpconditions/xpconditions_test.go rename to move/pkg/xpconditions/xpconditions_test.go diff --git a/pkg/xpenvfuncs/xpenvfuncs.go b/move/pkg/xpenvfuncs/xpenvfuncs.go similarity index 100% rename from pkg/xpenvfuncs/xpenvfuncs.go rename to move/pkg/xpenvfuncs/xpenvfuncs.go diff --git a/pkg/xpenvfuncs/xpenvfuncs_test.go b/move/pkg/xpenvfuncs/xpenvfuncs_test.go similarity index 100% rename from pkg/xpenvfuncs/xpenvfuncs_test.go rename to move/pkg/xpenvfuncs/xpenvfuncs_test.go From 6d47ffc219d99ef90326f77db81bfea1948e5d7e Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Fri, 20 Oct 2023 17:16:20 +0200 Subject: [PATCH 19/23] fix references Signed-off-by: Maximilian Braun (SAP) --- move/go.mod | 2 +- move/pkg/images/lookup.go | 2 +- move/pkg/resources/resources.go | 2 +- move/pkg/setup/setup.go | 6 +++--- move/pkg/xpenvfuncs/xpenvfuncs.go | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/move/go.mod b/move/go.mod index f518141..fc588d6 100644 --- a/move/go.mod +++ b/move/go.mod @@ -1,4 +1,4 @@ -module github.com/maximilianbraun/xp-testing +module github.com/crossplane-contrib/xp-testing go 1.20 diff --git a/move/pkg/images/lookup.go b/move/pkg/images/lookup.go index d4b9622..6fec77c 100644 --- a/move/pkg/images/lookup.go +++ b/move/pkg/images/lookup.go @@ -6,7 +6,7 @@ import ( "github.com/pkg/errors" - "github.com/maximilianbraun/xp-testing/pkg/envvar" + "github.com/crossplane-contrib/xp-testing/pkg/envvar" ) const ( diff --git a/move/pkg/resources/resources.go b/move/pkg/resources/resources.go index 215057b..4ac33bb 100644 --- a/move/pkg/resources/resources.go +++ b/move/pkg/resources/resources.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/maximilianbraun/xp-testing/pkg/xpconditions" + "github.com/crossplane-contrib/xp-testing/pkg/xpconditions" crossplanev1 "github.com/crossplane/crossplane/apis/pkg/v1" "github.com/samber/lo" diff --git a/move/pkg/setup/setup.go b/move/pkg/setup/setup.go index 6e35d44..0446f01 100644 --- a/move/pkg/setup/setup.go +++ b/move/pkg/setup/setup.go @@ -4,7 +4,7 @@ import ( "os" "strings" - "github.com/maximilianbraun/xp-testing/pkg/envvar" + "github.com/crossplane-contrib/xp-testing/pkg/envvar" "github.com/crossplane/crossplane/apis/pkg/v1alpha1" "github.com/vladimirvivien/gexe" @@ -14,8 +14,8 @@ import ( "sigs.k8s.io/e2e-framework/pkg/envconf" "sigs.k8s.io/e2e-framework/pkg/envfuncs" - "github.com/maximilianbraun/xp-testing/pkg/images" - "github.com/maximilianbraun/xp-testing/pkg/xpenvfuncs" + "github.com/crossplane-contrib/xp-testing/pkg/images" + "github.com/crossplane-contrib/xp-testing/pkg/xpenvfuncs" ) const ( diff --git a/move/pkg/xpenvfuncs/xpenvfuncs.go b/move/pkg/xpenvfuncs/xpenvfuncs.go index bd82b2e..4c3efa9 100644 --- a/move/pkg/xpenvfuncs/xpenvfuncs.go +++ b/move/pkg/xpenvfuncs/xpenvfuncs.go @@ -30,12 +30,12 @@ import ( "sigs.k8s.io/e2e-framework/third_party/helm" "sigs.k8s.io/kind/pkg/cluster" - resHelper "github.com/maximilianbraun/xp-testing/pkg/resources" - xconditions "github.com/maximilianbraun/xp-testing/pkg/xpconditions" + resHelper "github.com/crossplane-contrib/xp-testing/pkg/resources" + xconditions "github.com/crossplane-contrib/xp-testing/pkg/xpconditions" - "github.com/maximilianbraun/xp-testing/internal/docker" - "github.com/maximilianbraun/xp-testing/internal/xpkg" - "github.com/maximilianbraun/xp-testing/pkg/xpconditions" + "github.com/crossplane-contrib/xp-testing/internal/docker" + "github.com/crossplane-contrib/xp-testing/internal/xpkg" + "github.com/crossplane-contrib/xp-testing/pkg/xpconditions" ) const crsCrossplaneCacheVolumeTemplate = `apiVersion: v1 From c87f63cfe3f6b65c81cae9a044cd337b2384f3eb Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Mon, 23 Oct 2023 18:30:20 +0200 Subject: [PATCH 20/23] comply with latest golangci-lint requirements Signed-off-by: Maximilian Braun (SAP) --- move/.editorconfig | 1 + move/internal/docker/docker_test.go | 26 +++++++-------- move/internal/xpkg/xpkg_test.go | 24 +++++++------- move/pkg/envvar/envvar_test.go | 30 ++++++++--------- move/pkg/images/lookup_test.go | 14 ++++---- move/pkg/logging/logging_test.go | 6 ++-- move/pkg/setup/setup_test.go | 6 ++-- move/pkg/xpenvfuncs/xpenvfuncs_test.go | 46 +++++++++++++------------- 8 files changed, 77 insertions(+), 76 deletions(-) diff --git a/move/.editorconfig b/move/.editorconfig index 288a6a1..af28a32 100644 --- a/move/.editorconfig +++ b/move/.editorconfig @@ -10,6 +10,7 @@ indent_size = 2 [{Makefile,go.mod,go.sum,*.go,.gitmodules}] indent_style = tab indent_size = 4 +ij_go_import_sorting = goimports [*.md] indent_size = 4 diff --git a/move/internal/docker/docker_test.go b/move/internal/docker/docker_test.go index 259bbcb..5082566 100644 --- a/move/internal/docker/docker_test.go +++ b/move/internal/docker/docker_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSave(t *testing.T) { @@ -74,17 +74,17 @@ func TestSave(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { runDocker = func(command string, options ...string) error { - assert.Equal(t, "save", command) - assert.Equal(t, test.expects.options, options) + require.Equal(t, "save", command) + require.Equal(t, test.expects.options, options) return test.args.returnError } err := Save(test.args.image, test.args.target) if len(test.expects.errorMessage) == 0 { - assert.NoError(t, err) + require.NoError(t, err) } else { - assert.EqualError(t, err, test.expects.errorMessage) + require.EqualError(t, err, test.expects.errorMessage) } }) } @@ -167,17 +167,17 @@ func TestCp(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { runDocker = func(command string, options ...string) error { - assert.Equal(t, "cp", command) - assert.Equal(t, test.expects.options, options) + require.Equal(t, "cp", command) + require.Equal(t, test.expects.options, options) return test.args.returnError } err := Cp(test.args.source, test.args.target) if len(test.expects.errorMessage) == 0 { - assert.NoError(t, err) + require.NoError(t, err) } else { - assert.EqualError(t, err, test.expects.errorMessage) + require.EqualError(t, err, test.expects.errorMessage) } }) } @@ -263,17 +263,17 @@ func TestExec(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { runDocker = func(command string, options ...string) error { - assert.Equal(t, "exec", command) - assert.Equal(t, test.expects.options, options) + require.Equal(t, "exec", command) + require.Equal(t, test.expects.options, options) return test.args.returnError } err := Exec(test.args.container, test.args.command, test.args.options...) if len(test.expects.errorMessage) == 0 { - assert.NoError(t, err) + require.NoError(t, err) } else { - assert.EqualError(t, err, test.expects.errorMessage) + require.EqualError(t, err, test.expects.errorMessage) } }) } diff --git a/move/internal/xpkg/xpkg_test.go b/move/internal/xpkg/xpkg_test.go index 3e699d9..117fb73 100644 --- a/move/internal/xpkg/xpkg_test.go +++ b/move/internal/xpkg/xpkg_test.go @@ -9,7 +9,7 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const csdProvider = `apiVersion: pkg.crossplane.io/v1 @@ -22,7 +22,7 @@ spec: func returnStaticXPKG(t *testing.T, expectedImage string, returnContent string, returnError error) func(string, string) error { return func(image string, path string) error { - assert.Equal(t, expectedImage, image) + require.Equal(t, expectedImage, image) if returnError != nil { return returnError @@ -84,11 +84,11 @@ func TestFetchPackageContent(t *testing.T) { pkgContent, err := FetchPackageContent(test.args.crossplanePackage) if len(test.expects.errorMessage) == 0 { - if assert.NoError(t, err) { - assert.Equal(t, test.expects.crossplanePackageContent, pkgContent) + if err == nil { + require.Equal(t, test.expects.crossplanePackageContent, pkgContent) } } else { - assert.EqualError(t, err, test.expects.errorMessage) + require.EqualError(t, err, test.expects.errorMessage) } }) } @@ -135,17 +135,17 @@ func TestSavePackage(t *testing.T) { t.Run(test.description, func(t *testing.T) { extractContainerImage = returnStaticXPKG(t, test.args.crossplanePackage, test.args.returnContent, test.args.returnError) - if tmpFile, err := os.CreateTemp("", "test"); assert.NoError(t, err) { + if tmpFile, err := os.CreateTemp("", "test"); err == nil { defer os.Remove(tmpFile.Name()) - err := SavePackage(test.args.crossplanePackage, tmpFile.Name()) + err = SavePackage(test.args.crossplanePackage, tmpFile.Name()) if len(test.expects.errorMessage) == 0 { - if assert.NoError(t, err) { + if err == nil { assertSHA256(t, tmpFile.Name(), test.expects.fileChecksum) } } else { - assert.EqualError(t, err, test.expects.errorMessage) + require.EqualError(t, err, test.expects.errorMessage) } } }) @@ -153,12 +153,12 @@ func TestSavePackage(t *testing.T) { } func assertSHA256(t *testing.T, file string, expectedSHA256 string) { - if f, err := os.Open(file); assert.NoError(t, err) { + if f, err := os.Open(file); err == nil { defer f.Close() hasher := sha256.New() - if _, err := io.Copy(hasher, f); assert.NoError(t, err) { - assert.Equal(t, expectedSHA256, hex.EncodeToString(hasher.Sum(nil))) + if _, err := io.Copy(hasher, f); err == nil { + require.Equal(t, expectedSHA256, hex.EncodeToString(hasher.Sum(nil))) } } } diff --git a/move/pkg/envvar/envvar_test.go b/move/pkg/envvar/envvar_test.go index d41bc2f..87fe61c 100644 --- a/move/pkg/envvar/envvar_test.go +++ b/move/pkg/envvar/envvar_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -31,36 +31,36 @@ func (suite *EnvVarTestSuite) TearDownTest() { func (suite *EnvVarTestSuite) TestGet() { suite.T().Run("Returns existing env vars", func(t *testing.T) { - assert.Equal(t, "", Get("ENVVARTEST_EMPTY")) - assert.Equal(t, "This is a single line", Get("ENVVARTEST_SINGLE")) - assert.Equal(t, "This\nis\na multiline string!", Get("ENVVARTEST_MULTILINE")) + require.Equal(t, "", Get("ENVVARTEST_EMPTY")) + require.Equal(t, "This is a single line", Get("ENVVARTEST_SINGLE")) + require.Equal(t, "This\nis\na multiline string!", Get("ENVVARTEST_MULTILINE")) }) suite.T().Run("Returns empty string if env var can't be found", func(t *testing.T) { - assert.Empty(suite.T(), Get("ENVVARTEST_DOESNT_EXIST")) + suite.Require().Empty(Get("ENVVARTEST_DOESNT_EXIST")) }) } func (suite *EnvVarTestSuite) TestGetOrDefault() { suite.T().Run("Returns existing env vars", func(t *testing.T) { - assert.Equal(t, "", GetOrDefault("ENVVARTEST_EMPTY", "")) - assert.Equal(t, "This is a single line", GetOrDefault("ENVVARTEST_SINGLE", "")) - assert.Equal(t, "This\nis\na multiline string!", GetOrDefault("ENVVARTEST_MULTILINE", "")) + require.Equal(t, "", GetOrDefault("ENVVARTEST_EMPTY", "")) + require.Equal(t, "This is a single line", GetOrDefault("ENVVARTEST_SINGLE", "")) + require.Equal(t, "This\nis\na multiline string!", GetOrDefault("ENVVARTEST_MULTILINE", "")) }) suite.T().Run("Returns default value if env var can't be found", func(t *testing.T) { - assert.Equal(t, "a default value", GetOrDefault("ENVVARTEST_DOESNT_EXIST", "a default value")) - assert.Equal(t, "another default value", GetOrDefault("ENVVARTEST_DOESNT_EXIST", "another default value")) + require.Equal(t, "a default value", GetOrDefault("ENVVARTEST_DOESNT_EXIST", "a default value")) + require.Equal(t, "another default value", GetOrDefault("ENVVARTEST_DOESNT_EXIST", "another default value")) }) } func (suite *EnvVarTestSuite) TestGetOrPanic() { suite.T().Run("Returns existing env vars", func(t *testing.T) { - assert.Equal(t, "", GetOrPanic("ENVVARTEST_EMPTY")) - assert.Equal(t, "This is a single line", GetOrPanic("ENVVARTEST_SINGLE")) - assert.Equal(t, "This\nis\na multiline string!", GetOrPanic("ENVVARTEST_MULTILINE")) + require.Equal(t, "", GetOrPanic("ENVVARTEST_EMPTY")) + require.Equal(t, "This is a single line", GetOrPanic("ENVVARTEST_SINGLE")) + require.Equal(t, "This\nis\na multiline string!", GetOrPanic("ENVVARTEST_MULTILINE")) }) suite.T().Run("Panics if env var can't be found", func(t *testing.T) { - assert.Panics(t, func() { GetOrPanic("ENVVARTEST_DOESNT_EXIST") }) - assert.Panics(t, func() { GetOrPanic("ENVVARTEST_DOESNT_EXIST") }) + require.Panics(t, func() { GetOrPanic("ENVVARTEST_DOESNT_EXIST") }) + require.Panics(t, func() { GetOrPanic("ENVVARTEST_DOESNT_EXIST") }) }) } diff --git a/move/pkg/images/lookup_test.go b/move/pkg/images/lookup_test.go index e3a3623..1dba751 100644 --- a/move/pkg/images/lookup_test.go +++ b/move/pkg/images/lookup_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -24,27 +24,27 @@ func (suite *LookupSuite) TestGetImagesFromJSONOrPanic() { err := os.Setenv("E2E_IMAGES", "{\"foo\": \"bar\", \"baz\": \"boom\"}") println(err) providerImages := GetImagesFromEnvironmentOrPanic(packageKey, &controllerKey) - assert.Equal(t, "bar", providerImages.Package) - assert.Equal(t, "boom", *providerImages.ControllerImage) + require.Equal(t, "bar", providerImages.Package) + require.Equal(t, "boom", *providerImages.ControllerImage) }) suite.T().Run("Returns existing env vars", func(t *testing.T) { os.Setenv("E2E_IMAGES", "{\"foo\": \"bar\"}") providerImages := GetImagesFromEnvironmentOrPanic(packageKey, nil) - assert.Equal(t, "bar", providerImages.Package) - assert.Nil(t, providerImages.ControllerImage) + require.Equal(t, "bar", providerImages.Package) + require.Nil(t, providerImages.ControllerImage) }) suite.T().Run("env var not set, will panic", func(t *testing.T) { os.Unsetenv("E2E_IMAGES") - assert.Panics(t, func() { + require.Panics(t, func() { GetImagesFromEnvironmentOrPanic(packageKey, nil) }) }) suite.T().Run("invalid json, will panic", func(t *testing.T) { os.Setenv("E2E_IMAGES", "//invalid.json") - assert.Panics(t, func() { + require.Panics(t, func() { GetImagesFromEnvironmentOrPanic(packageKey, nil) }) }) diff --git a/move/pkg/logging/logging_test.go b/move/pkg/logging/logging_test.go index aa3224d..bf02897 100644 --- a/move/pkg/logging/logging_test.go +++ b/move/pkg/logging/logging_test.go @@ -4,7 +4,7 @@ import ( "flag" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestEnableVerboseLogging(t *testing.T) { @@ -14,7 +14,7 @@ func TestEnableVerboseLogging(t *testing.T) { EnableVerboseLogging(nil) verbseFlag := flag.Lookup("v") - assert.Equal(t, verbseFlag.Value.String(), "4") + require.Equal(t, "4", verbseFlag.Value.String()) }, ) t.Run( @@ -24,7 +24,7 @@ func TestEnableVerboseLogging(t *testing.T) { EnableVerboseLogging(ptr(10)) verbseFlag := flag.Lookup("v") - assert.Equal(t, verbseFlag.Value.String(), "10") + require.Equal(t, "10", verbseFlag.Value.String()) }, ) } diff --git a/move/pkg/setup/setup_test.go b/move/pkg/setup/setup_test.go index e4de14a..0a52b32 100644 --- a/move/pkg/setup/setup_test.go +++ b/move/pkg/setup/setup_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var someName = "Bar" @@ -66,9 +66,9 @@ func Test_clusterName(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.args.clusterNameEnvValue == nil { - assert.NoError(t, os.Unsetenv(clusterNameEnv)) + require.NoError(t, os.Unsetenv(clusterNameEnv)) } else { - assert.NoError(t, os.Setenv(clusterNameEnv, *tt.args.clusterNameEnvValue)) + require.NoError(t, os.Setenv(clusterNameEnv, *tt.args.clusterNameEnvValue)) } if got := clusterName(tt.args.reuseCluster); !tt.matcher(got) { t.Errorf("clusterName() = %v; matcher returned error", got) diff --git a/move/pkg/xpenvfuncs/xpenvfuncs_test.go b/move/pkg/xpenvfuncs/xpenvfuncs_test.go index d3e2d5b..e36cb3f 100644 --- a/move/pkg/xpenvfuncs/xpenvfuncs_test.go +++ b/move/pkg/xpenvfuncs/xpenvfuncs_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/pkg/errors" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/e2e-framework/pkg/env" "sigs.k8s.io/e2e-framework/pkg/envconf" ) @@ -31,8 +31,8 @@ func TestCompose(t *testing.T) { ctx, err := Compose()(pctx, nil) - assert.NoError(t, err) - assert.Equal(t, pctx, ctx) + require.NoError(t, err) + require.Equal(t, pctx, ctx) }, ) @@ -46,15 +46,15 @@ func TestCompose(t *testing.T) { ctx, err := Compose( func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { invoked = true - assert.Equal(t, pctx, ctx) - assert.Equal(t, pcfg, cfg) + require.Equal(t, pctx, ctx) + require.Equal(t, pcfg, cfg) return ctx, nil }, )(pctx, pcfg) - assert.True(t, invoked) - assert.NoError(t, err) - assert.Equal(t, pctx, ctx) + require.True(t, invoked) + require.NoError(t, err) + require.Equal(t, pctx, ctx) }, ) @@ -68,8 +68,8 @@ func TestCompose(t *testing.T) { incEnvFunc(&invocations), )(context.Background(), &envconf.Config{}) - assert.NoError(t, err) - assert.Equal(t, 3, invocations) + require.NoError(t, err) + require.Equal(t, 3, invocations) }, ) @@ -84,14 +84,14 @@ func TestCompose(t *testing.T) { incEnvFunc(&invocations), )(context.Background(), &envconf.Config{}) - assert.EqualError(t, err, "stop here") - assert.Equal(t, 2, invocations) + require.EqualError(t, err, "stop here") + require.Equal(t, 2, invocations) }, ) } func TestGetClusterControlPlaneName(t *testing.T) { - assert.Equal(t, "my-cluster-control-plane", getClusterControlPlaneName("my-cluster")) + require.Equal(t, "my-cluster-control-plane", getClusterControlPlaneName("my-cluster")) } func TestRenderTemplate(t *testing.T) { @@ -238,15 +238,15 @@ spec: for _, test := range tests { t.Run( test.description, func(t *testing.T) { - assert.True(t, true) + require.True(t, true) rendered, err := renderTemplate(test.args.template, test.args.data) if len(test.expects.errorMessage) == 0 { - if assert.NoError(t, err) { - assert.Equal(t, test.expects.rendered, rendered) + if err == nil { + require.Equal(t, test.expects.rendered, rendered) } } else { - assert.Error(t, err) + require.Error(t, err) } }, ) @@ -261,7 +261,7 @@ func TestDummyErr(t *testing.T) { t.Run( "dummyErrFunc returns error", func(t *testing.T) { _, err := dummyErrFunc(nil, nil) - assert.Error(t, err) + require.Error(t, err) }, ) } @@ -271,14 +271,14 @@ func TestConditional(t *testing.T) { "executes", func(t *testing.T) { conditionalFn := Conditional(dummyErrFunc, true) _, err := conditionalFn(nil, nil) - assert.Error(t, err) + require.Error(t, err) }, ) t.Run( "doesnt execute", func(t *testing.T) { conditionalFn := Conditional(dummyErrFunc, false) _, err := conditionalFn(nil, nil) - assert.NoError(t, err) + require.NoError(t, err) }, ) } @@ -288,7 +288,7 @@ func TestIgnoreErr(t *testing.T) { "no error thown", func(t *testing.T) { conditionalFn := IgnoreErr(dummyErrFunc) _, err := conditionalFn(nil, nil) - assert.NoError(t, err) + require.NoError(t, err) }, ) } @@ -300,7 +300,7 @@ func TestIgnoreMatchedErr(t *testing.T) { return false }) _, err := conditionalFn(nil, nil) - assert.NoError(t, err) + require.NoError(t, err) }, ) @@ -310,7 +310,7 @@ func TestIgnoreMatchedErr(t *testing.T) { return true }) _, err := conditionalFn(nil, nil) - assert.NoError(t, err) + require.NoError(t, err) }, ) } From 59bd55e53b2101612575025aaa71adcbf27642ff Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Mon, 23 Oct 2023 18:30:52 +0200 Subject: [PATCH 21/23] set golangcilint version Signed-off-by: Maximilian Braun (SAP) --- move/.github/workflows/lint.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/move/.github/workflows/lint.yaml b/move/.github/workflows/lint.yaml index 4812426..8e1a288 100644 --- a/move/.github/workflows/lint.yaml +++ b/move/.github/workflows/lint.yaml @@ -27,7 +27,7 @@ jobs: uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - # version: v1.29 + version: v1.55 # Optional: working directory, useful for monorepos # working-directory: somedir From 4bbefc1e05d8cf5c12779be806f75401fde889cf Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Tue, 31 Oct 2023 11:14:10 +0100 Subject: [PATCH 22/23] chore: compelte move Signed-off-by: Maximilian Braun (SAP) --- move/.editorconfig => .editorconfig | 0 {move/.github => .github}/workflows/codeql.yml | 0 {move/.github => .github}/workflows/lint.yaml | 0 move/.gitignore => .gitignore | 0 move/.golangci.yml => .golangci.yml | 0 move/DCO => DCO | 0 move/LICENSE => LICENSE | 0 move/README.md => README.md | 0 move/go.mod => go.mod | 0 move/go.sum => go.sum | 0 {move/internal => internal}/docker/docker.go | 0 {move/internal => internal}/docker/docker_test.go | 0 {move/internal => internal}/xpkg/xpkg.go | 0 {move/internal => internal}/xpkg/xpkg_test.go | 0 {move/pkg => pkg}/envvar/envvar.go | 0 {move/pkg => pkg}/envvar/envvar_test.go | 0 {move/pkg => pkg}/images/lookup.go | 0 {move/pkg => pkg}/images/lookup_test.go | 0 {move/pkg => pkg}/logging/logging.go | 0 {move/pkg => pkg}/logging/logging_test.go | 0 {move/pkg => pkg}/resources/resources.go | 0 {move/pkg => pkg}/setup/setup.go | 0 {move/pkg => pkg}/setup/setup_test.go | 0 {move/pkg => pkg}/xpconditions/xpconditions.go | 0 {move/pkg => pkg}/xpconditions/xpconditions_test.go | 0 {move/pkg => pkg}/xpenvfuncs/xpenvfuncs.go | 0 {move/pkg => pkg}/xpenvfuncs/xpenvfuncs_test.go | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename move/.editorconfig => .editorconfig (100%) rename {move/.github => .github}/workflows/codeql.yml (100%) rename {move/.github => .github}/workflows/lint.yaml (100%) rename move/.gitignore => .gitignore (100%) rename move/.golangci.yml => .golangci.yml (100%) rename move/DCO => DCO (100%) rename move/LICENSE => LICENSE (100%) rename move/README.md => README.md (100%) rename move/go.mod => go.mod (100%) rename move/go.sum => go.sum (100%) rename {move/internal => internal}/docker/docker.go (100%) rename {move/internal => internal}/docker/docker_test.go (100%) rename {move/internal => internal}/xpkg/xpkg.go (100%) rename {move/internal => internal}/xpkg/xpkg_test.go (100%) rename {move/pkg => pkg}/envvar/envvar.go (100%) rename {move/pkg => pkg}/envvar/envvar_test.go (100%) rename {move/pkg => pkg}/images/lookup.go (100%) rename {move/pkg => pkg}/images/lookup_test.go (100%) rename {move/pkg => pkg}/logging/logging.go (100%) rename {move/pkg => pkg}/logging/logging_test.go (100%) rename {move/pkg => pkg}/resources/resources.go (100%) rename {move/pkg => pkg}/setup/setup.go (100%) rename {move/pkg => pkg}/setup/setup_test.go (100%) rename {move/pkg => pkg}/xpconditions/xpconditions.go (100%) rename {move/pkg => pkg}/xpconditions/xpconditions_test.go (100%) rename {move/pkg => pkg}/xpenvfuncs/xpenvfuncs.go (100%) rename {move/pkg => pkg}/xpenvfuncs/xpenvfuncs_test.go (100%) diff --git a/move/.editorconfig b/.editorconfig similarity index 100% rename from move/.editorconfig rename to .editorconfig diff --git a/move/.github/workflows/codeql.yml b/.github/workflows/codeql.yml similarity index 100% rename from move/.github/workflows/codeql.yml rename to .github/workflows/codeql.yml diff --git a/move/.github/workflows/lint.yaml b/.github/workflows/lint.yaml similarity index 100% rename from move/.github/workflows/lint.yaml rename to .github/workflows/lint.yaml diff --git a/move/.gitignore b/.gitignore similarity index 100% rename from move/.gitignore rename to .gitignore diff --git a/move/.golangci.yml b/.golangci.yml similarity index 100% rename from move/.golangci.yml rename to .golangci.yml diff --git a/move/DCO b/DCO similarity index 100% rename from move/DCO rename to DCO diff --git a/move/LICENSE b/LICENSE similarity index 100% rename from move/LICENSE rename to LICENSE diff --git a/move/README.md b/README.md similarity index 100% rename from move/README.md rename to README.md diff --git a/move/go.mod b/go.mod similarity index 100% rename from move/go.mod rename to go.mod diff --git a/move/go.sum b/go.sum similarity index 100% rename from move/go.sum rename to go.sum diff --git a/move/internal/docker/docker.go b/internal/docker/docker.go similarity index 100% rename from move/internal/docker/docker.go rename to internal/docker/docker.go diff --git a/move/internal/docker/docker_test.go b/internal/docker/docker_test.go similarity index 100% rename from move/internal/docker/docker_test.go rename to internal/docker/docker_test.go diff --git a/move/internal/xpkg/xpkg.go b/internal/xpkg/xpkg.go similarity index 100% rename from move/internal/xpkg/xpkg.go rename to internal/xpkg/xpkg.go diff --git a/move/internal/xpkg/xpkg_test.go b/internal/xpkg/xpkg_test.go similarity index 100% rename from move/internal/xpkg/xpkg_test.go rename to internal/xpkg/xpkg_test.go diff --git a/move/pkg/envvar/envvar.go b/pkg/envvar/envvar.go similarity index 100% rename from move/pkg/envvar/envvar.go rename to pkg/envvar/envvar.go diff --git a/move/pkg/envvar/envvar_test.go b/pkg/envvar/envvar_test.go similarity index 100% rename from move/pkg/envvar/envvar_test.go rename to pkg/envvar/envvar_test.go diff --git a/move/pkg/images/lookup.go b/pkg/images/lookup.go similarity index 100% rename from move/pkg/images/lookup.go rename to pkg/images/lookup.go diff --git a/move/pkg/images/lookup_test.go b/pkg/images/lookup_test.go similarity index 100% rename from move/pkg/images/lookup_test.go rename to pkg/images/lookup_test.go diff --git a/move/pkg/logging/logging.go b/pkg/logging/logging.go similarity index 100% rename from move/pkg/logging/logging.go rename to pkg/logging/logging.go diff --git a/move/pkg/logging/logging_test.go b/pkg/logging/logging_test.go similarity index 100% rename from move/pkg/logging/logging_test.go rename to pkg/logging/logging_test.go diff --git a/move/pkg/resources/resources.go b/pkg/resources/resources.go similarity index 100% rename from move/pkg/resources/resources.go rename to pkg/resources/resources.go diff --git a/move/pkg/setup/setup.go b/pkg/setup/setup.go similarity index 100% rename from move/pkg/setup/setup.go rename to pkg/setup/setup.go diff --git a/move/pkg/setup/setup_test.go b/pkg/setup/setup_test.go similarity index 100% rename from move/pkg/setup/setup_test.go rename to pkg/setup/setup_test.go diff --git a/move/pkg/xpconditions/xpconditions.go b/pkg/xpconditions/xpconditions.go similarity index 100% rename from move/pkg/xpconditions/xpconditions.go rename to pkg/xpconditions/xpconditions.go diff --git a/move/pkg/xpconditions/xpconditions_test.go b/pkg/xpconditions/xpconditions_test.go similarity index 100% rename from move/pkg/xpconditions/xpconditions_test.go rename to pkg/xpconditions/xpconditions_test.go diff --git a/move/pkg/xpenvfuncs/xpenvfuncs.go b/pkg/xpenvfuncs/xpenvfuncs.go similarity index 100% rename from move/pkg/xpenvfuncs/xpenvfuncs.go rename to pkg/xpenvfuncs/xpenvfuncs.go diff --git a/move/pkg/xpenvfuncs/xpenvfuncs_test.go b/pkg/xpenvfuncs/xpenvfuncs_test.go similarity index 100% rename from move/pkg/xpenvfuncs/xpenvfuncs_test.go rename to pkg/xpenvfuncs/xpenvfuncs_test.go From ba5fa707004bb0f5615df72e5606fe5d2ee954b2 Mon Sep 17 00:00:00 2001 From: "Maximilian Braun (SAP)" Date: Tue, 31 Oct 2023 12:56:42 +0100 Subject: [PATCH 23/23] fix: conflicts in Readme Signed-off-by: Maximilian Braun (SAP) --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index 5c9beff..64c3529 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,3 @@ -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -# xp-testing -======= -# xp-testiing ->>>>>>> 352ec62 (Initial commit) -======= -# xp-testing ->>>>>>> 478ccae (Update README.md) -======= # End-to-end test framework for Crossplane providers `xp-testing` is a library enabling end-to-end tests for Crossplane providers, based on @@ -75,4 +64,3 @@ xp-testing is under the Apache 2.0 license. Initially developed by [v0lkc](https://github.com/v0lkc), [mirzakopic](https://github.com/mirzakopic) and their team at [SAP](https://github.com/SAP/). ->>>>>>> 1387da7 (chore: README.md)