├── .gimps.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── pull_request_template.md └── workflows │ ├── docs-gen-and-push.yaml │ └── release.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yaml ├── .prow.yaml ├── .wwhrd.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DCO ├── Dockerfile ├── GOVERNANCE.md ├── LICENSE ├── Makefile ├── Makefile.venv ├── OWNERS ├── README.md ├── cmd ├── api-syncagent │ ├── main.go │ └── options.go └── crd-puller │ ├── .gitignore │ ├── README.md │ └── main.go ├── deploy └── crd │ └── kcp.io │ └── syncagent.kcp.io_publishedresources.yaml ├── docs ├── .gitignore ├── content │ ├── .pages │ ├── README.md │ ├── consuming-services.md │ ├── contributing │ │ └── releasing.md │ ├── faq.md │ ├── getting-started.md │ ├── publish-resources │ │ ├── .pages │ │ ├── api-lifecycle.md │ │ ├── index.md │ │ ├── technical-details.md │ │ └── templating.md │ └── reference │ │ ├── .gitignore │ │ ├── .pages │ │ └── index.md ├── generators │ └── crd-ref │ │ ├── config.yaml │ │ ├── crd.template.md │ │ └── run-crd-ref-gen.sh ├── main.py ├── mkdocs.yml ├── overrides │ ├── favicons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ └── mstile-150x150.png │ ├── icons │ │ └── logo.svg │ ├── logo.svg │ ├── partials │ │ ├── outdated.html │ │ └── section-overview.html │ └── stylesheets │ │ └── crd.css ├── requirements.txt └── scripts │ ├── deploy-docs.sh │ └── serve-docs.sh ├── go.mod ├── go.sum ├── hack ├── boilerplate │ ├── boilerplate.Dockerfile.txt │ ├── boilerplate.go.txt │ ├── boilerplate.sh.txt │ ├── boilerplate.yaml.txt │ ├── boilerplate.yml.txt │ └── generated │ │ └── boilerplate.go.txt ├── ci │ ├── build-image.sh │ ├── run-e2e-tests.sh │ ├── testdata │ │ └── e2e-kcp.tokens │ └── verify.sh ├── download-tool.sh ├── lib.sh ├── reconciling.yaml ├── run-tests.sh ├── tools.go ├── update-codegen-crds.sh ├── update-codegen-sdk.sh ├── verify-boilerplate.sh └── verify-licenses.sh ├── internal ├── controller │ ├── apiexport │ │ ├── controller.go │ │ ├── doc.go │ │ └── reconciler.go │ ├── apiresourceschema │ │ ├── controller.go │ │ └── doc.go │ ├── sync │ │ ├── controller.go │ │ └── doc.go │ └── syncmanager │ │ ├── controller.go │ │ ├── doc.go │ │ └── lifecycle │ │ ├── cluster.go │ │ └── controller.go ├── controllerutil │ ├── handler.go │ └── predicate │ │ └── predicate.go ├── crypto │ └── hash.go ├── discovery │ └── client.go ├── kcp │ └── types.go ├── log │ └── zap.go ├── mutation │ ├── mutation.go │ ├── mutation_test.go │ └── mutator.go ├── options │ ├── options.go │ └── set_flag.go ├── projection │ ├── projection.go │ └── projection_test.go ├── resources │ └── reconciling │ │ └── zz_generated_reconcile.go ├── sync │ ├── apis │ │ └── dummy │ │ │ └── v1alpha1 │ │ │ ├── doc.go │ │ │ ├── register.go │ │ │ ├── thing.go │ │ │ ├── thing_namespaced.go │ │ │ ├── thing_real_status.go │ │ │ ├── thing_status.go │ │ │ └── zz_generated.deepcopy.go │ ├── context.go │ ├── context_test.go │ ├── crd │ │ ├── dummy.example.com_namespacedthings.yaml │ │ ├── dummy.example.com_things.yaml │ │ ├── dummy.example.com_thingwithstatuses.yaml │ │ └── dummy.example.com_thingwithstatussubresources.yaml │ ├── init_test.go │ ├── meta.go │ ├── meta_test.go │ ├── metadata.go │ ├── object_syncer.go │ ├── state_store.go │ ├── state_store_test.go │ ├── syncer.go │ ├── syncer_related.go │ ├── syncer_related_test.go │ ├── syncer_test.go │ ├── templating │ │ ├── naming.go │ │ ├── naming_test.go │ │ ├── related.go │ │ ├── templating.go │ │ └── templating_test.go │ └── types.go ├── test │ └── diff │ │ └── diff.go └── version │ └── app.go ├── sdk ├── LICENSE ├── apis │ └── syncagent │ │ └── v1alpha1 │ │ ├── doc.go │ │ ├── published_resource.go │ │ ├── register.go │ │ ├── types.go │ │ └── zz_generated.deepcopy.go ├── applyconfiguration │ ├── internal │ │ └── internal.go │ ├── syncagent │ │ └── v1alpha1 │ │ │ ├── publishedresource.go │ │ │ ├── publishedresourcespec.go │ │ │ ├── publishedresourcestatus.go │ │ │ ├── regularexpression.go │ │ │ ├── relatedresourceobject.go │ │ │ ├── relatedresourceobjectreference.go │ │ │ ├── relatedresourceobjectselector.go │ │ │ ├── relatedresourceobjectspec.go │ │ │ ├── relatedresourceselectorrewrite.go │ │ │ ├── relatedresourcespec.go │ │ │ ├── resourcedeletemutation.go │ │ │ ├── resourcefilter.go │ │ │ ├── resourcemutation.go │ │ │ ├── resourcemutationspec.go │ │ │ ├── resourcenaming.go │ │ │ ├── resourceprojection.go │ │ │ ├── resourceregexmutation.go │ │ │ ├── resourcetemplatemutation.go │ │ │ ├── sourceresourcedescriptor.go │ │ │ └── templateexpression.go │ └── utils.go ├── clientset │ └── versioned │ │ ├── clientset.go │ │ ├── cluster │ │ ├── clientset.go │ │ ├── fake │ │ │ └── clientset.go │ │ ├── scheme │ │ │ └── register.go │ │ └── typed │ │ │ └── syncagent │ │ │ └── v1alpha1 │ │ │ ├── fake │ │ │ ├── publishedresource.go │ │ │ └── syncagent_client.go │ │ │ ├── publishedresource.go │ │ │ └── syncagent_client.go │ │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ │ └── typed │ │ └── syncagent │ │ └── v1alpha1 │ │ ├── doc.go │ │ ├── fake │ │ ├── doc.go │ │ ├── fake_publishedresource.go │ │ └── fake_syncagent_client.go │ │ ├── generated_expansion.go │ │ ├── publishedresource.go │ │ └── syncagent_client.go ├── go.mod ├── go.sum ├── informers │ └── externalversions │ │ ├── factory.go │ │ ├── generic.go │ │ ├── internalinterfaces │ │ └── factory_interfaces.go │ │ └── syncagent │ │ ├── interface.go │ │ └── v1alpha1 │ │ ├── interface.go │ │ └── publishedresource.go └── listers │ └── syncagent │ └── v1alpha1 │ ├── publishedresource.go │ └── publishedresource_expansion.go └── test ├── crds ├── backup.go ├── backup.yaml ├── crontab-improved.yaml ├── crontab-multi-versions.yaml ├── crontab.go └── crontab.yaml ├── e2e ├── apiexport │ └── apiexport_test.go ├── apiresourceschema │ └── apiresourceschema_test.go ├── discovery │ └── discovery_test.go └── sync │ ├── primary_test.go │ └── related_test.go └── utils ├── fixtures.go ├── process.go ├── utils.go └── wait.go /.gimps.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is the configuration for https://codeberg.org/xrstf/gimps. 16 | 17 | importOrder: [std, external, project, kcp, kubernetes] 18 | sets: 19 | - name: kubernetes 20 | patterns: 21 | - 'k8s.io/**' 22 | - '*.k8s.io/**' 23 | - 'github.com/kcp-dev/client-go/**' 24 | - 'github.com/kcp-dev/kubernetes/**' 25 | - name: kcp 26 | patterns: 27 | - 'github.com/kcp-dev/kcp/**' 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve 3 | title: "bug: " 4 | labels: 5 | - kind/bug 6 | body: 7 | - type: textarea 8 | id: description 9 | attributes: 10 | label: Describe the bug 11 | description: Please provide a clear and concise description of the bug. 12 | placeholder: | 13 | Add logs and screenshots if any. 14 | validations: 15 | required: true 16 | 17 | - type: textarea 18 | id: reproducing 19 | attributes: 20 | label: Steps To Reproduce 21 | description: Steps to reproduce the behavior. 22 | placeholder: | 23 | 1. Go to '...' 24 | 2. Click on '...' 25 | 3. Scroll down to '...' 26 | 4. See the error 27 | validations: 28 | required: true 29 | 30 | - type: textarea 31 | id: expected 32 | attributes: 33 | label: Expected Behaviour 34 | description: A clear and concise description of what you expected to happen. 35 | validations: 36 | required: true 37 | 38 | - type: textarea 39 | id: additional 40 | attributes: 41 | label: Additional Context 42 | description: Add any other context about the problem here. 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea for this project 3 | title: "feature: " 4 | labels: 5 | - kind/feature 6 | body: 7 | - type: textarea 8 | id: problem 9 | attributes: 10 | label: Feature Description 11 | description: Is your feature request related to a problem? A clear and concise description of what the problem is. 12 | placeholder: I'm always frustrated when [...] 13 | validations: 14 | required: true 15 | 16 | - type: textarea 17 | id: solution 18 | attributes: 19 | label: Proposed Solution 20 | description: A clear and consise description of what you want to happen. 21 | placeholder: We can do [...] 22 | validations: 23 | required: true 24 | 25 | - type: textarea 26 | id: alternatives 27 | attributes: 28 | label: Alternative Solutions 29 | description: A clear and consise description of any alternative solutions or features that you've considered. 30 | placeholder: I think another approach would be [...] 31 | validations: 32 | required: false 33 | 34 | - type: checkboxes 35 | id: contribute 36 | attributes: 37 | label: Want to contribute? 38 | options: 39 | - label: I would like to work on this issue. 40 | required: false 41 | 42 | - type: textarea 43 | id: additional 44 | attributes: 45 | label: Additional Context 46 | description: Add any other context or screenshots about the feature request here. 47 | validations: 48 | required: false 49 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ## Summary 9 | 10 | ## What Type of PR Is This? 11 | 12 | 28 | 29 | ## Related Issue(s) 30 | 31 | Fixes # 32 | 33 | ## Release Notes 34 | 35 | 38 | 39 | ```release-note 40 | NONE 41 | ``` 42 | -------------------------------------------------------------------------------- /.github/workflows/docs-gen-and-push.yaml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | # So we can trigger manually if needed 5 | workflow_dispatch: 6 | # To confirm any changes to docs build successfully, without deploying them 7 | pull_request: 8 | # Pushes to branches do the full build + deployment 9 | push: 10 | branches: 11 | - main 12 | - "release-*" 13 | paths: 14 | - "cmd/**" 15 | - "docs/**" 16 | - "pkg/**" 17 | - ".github/workflows/docs-gen-and-push.yaml" 18 | 19 | permissions: 20 | contents: write 21 | 22 | concurrency: 23 | group: ${{ github.workflow }} 24 | 25 | jobs: 26 | generate-and-push: 27 | name: Generate and push 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 31 | 32 | - run: git fetch origin gh-pages 33 | - run: git fetch origin '+refs/tags/v*:refs/tags/v*' --no-tags 34 | 35 | - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # tag=v5.4.0 36 | with: 37 | go-version: v1.24.3 38 | cache: true 39 | 40 | - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 #tag=v5.5.0 41 | with: 42 | python-version: '3.10' 43 | cache: 'pip' 44 | 45 | # mike does not support giving CLI flags for mkdocs, but we also do not 46 | # want to permanently enable strict mode, so here we enable it just for this 47 | # task 48 | - run: | 49 | echo "strict: true" >> docs/mkdocs.yml 50 | 51 | - run: make generate-api-docs deploy-docs 52 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - .github/workflows/release.yml 7 | - .goreleaser.yaml 8 | push: 9 | tags: 10 | - 'v*' 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | release: 17 | runs-on: ubuntu-latest 18 | 19 | permissions: 20 | contents: write 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 25 | with: 26 | fetch-depth: 0 27 | 28 | - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # tag=v5.4.0 29 | with: 30 | go-version: v1.24.3 31 | cache: true 32 | 33 | - name: Delete non-semver tags 34 | run: 'git tag -d $(git tag -l | grep -v "^v")' 35 | 36 | - name: Set LDFLAGS 37 | run: echo LDFLAGS="$(make ldflags)" >> $GITHUB_ENV 38 | 39 | - name: Run GoReleaser on tag 40 | if: github.event_name != 'pull_request' 41 | uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # tag=v6.3.0 42 | with: 43 | distribution: goreleaser 44 | version: '~> v2' 45 | args: release --timeout 60m 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | 49 | - name: Run GoReleaser on pull request 50 | if: github.event_name == 'pull_request' 51 | uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # tag=v6.3.0 52 | with: 53 | distribution: goreleaser 54 | version: '~> v2' 55 | args: release --timeout 60m --snapshot 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | 59 | - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag=v4.6.2 60 | if: github.event_name == 'pull_request' 61 | with: 62 | name: binaries 63 | path: dist/*.tar.gz 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /_build/ 2 | /dist/ 3 | /_tools/ 4 | /vendor/ 5 | /.kcp.e2e/ 6 | /.e2e/ 7 | .cover 8 | *.kubeconfig 9 | *.pem 10 | *.key 11 | .DS_Store 12 | /docs/__pycache__ 13 | .idea/ 14 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | version: "2" 16 | run: 17 | modules-download-mode: readonly 18 | linters: 19 | default: none 20 | enable: 21 | - asciicheck 22 | - bidichk 23 | - bodyclose 24 | - copyloopvar 25 | - depguard 26 | - durationcheck 27 | - errcheck 28 | - errname 29 | - errorlint 30 | - goconst 31 | - gocritic 32 | - gocyclo 33 | - godot 34 | - govet 35 | - importas 36 | - ineffassign 37 | - misspell 38 | - noctx 39 | - nolintlint 40 | - nosprintfhostport 41 | - predeclared 42 | - promlinter 43 | - staticcheck 44 | - unconvert 45 | - unused 46 | - usetesting 47 | - wastedassign 48 | - whitespace 49 | settings: 50 | depguard: 51 | rules: 52 | main: 53 | deny: 54 | - pkg: io/ioutil 55 | desc: https://go.dev/doc/go1.16#ioutil 56 | - pkg: github.com/ghodss/yaml 57 | desc: use sigs.k8s.io/yaml instead 58 | importas: 59 | alias: 60 | # Sync Agent APIs 61 | - pkg: github.com/kcp-dev/api-syncagent/sdk/apis/(\w+)/(v[\w\d]+) 62 | alias: $1$2 63 | # Kubernetes 64 | - pkg: k8s.io/api/(\w+)/(v[\w\d]+) 65 | alias: $1$2 66 | - pkg: k8s.io/apimachinery/pkg/apis/meta/v1 67 | alias: metav1 68 | - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 69 | alias: apiextensionsv1 70 | - pkg: k8s.io/apimachinery/pkg/api/errors 71 | alias: apierrors 72 | - pkg: k8s.io/apimachinery/pkg/util/errors 73 | alias: utilerrors 74 | # Controller Runtime 75 | - pkg: sigs.k8s.io/controller-runtime/pkg/client 76 | alias: ctrlruntimeclient 77 | no-unaliased: true 78 | exclusions: 79 | generated: lax 80 | presets: 81 | - comments 82 | - common-false-positives 83 | - legacy 84 | - std-error-handling 85 | rules: 86 | # gocritic 87 | - path: (.+)\.go$ 88 | text: singleCaseSwitch # in most cases this is the beginning of a lookup table and should be kept an obvious table 89 | # staticcheck 90 | - path: (.+)\.go$ 91 | text: QF1008 # embedded field names in selectors often make the code more readable, though more verbose 92 | paths: 93 | - zz_generated.*.go 94 | - third_party$ 95 | - builtin$ 96 | - examples$ 97 | issues: 98 | # defaults to 3, which often needlessly hides issues and forces 99 | # to re-run the linter across the entire repo many times 100 | max-same-issues: 0 101 | formatters: 102 | enable: 103 | - gofmt 104 | exclusions: 105 | generated: lax 106 | paths: 107 | - zz_generated.*.go 108 | - third_party$ 109 | - builtin$ 110 | - examples$ 111 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | version: 2 16 | builds: 17 | - id: "api-syncagent" 18 | main: ./cmd/api-syncagent 19 | binary: api-syncagent 20 | ldflags: 21 | - "{{ .Env.LDFLAGS }}" 22 | goos: 23 | - linux 24 | - darwin 25 | goarch: 26 | - amd64 27 | - arm64 28 | env: 29 | - CGO_ENABLED=0 30 | 31 | archives: 32 | - id: api-syncagent 33 | ids: 34 | - api-syncagent 35 | 36 | release: 37 | draft: true 38 | mode: keep-existing 39 | -------------------------------------------------------------------------------- /.prow.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | presubmits: 16 | - name: pull-api-syncagent-verify 17 | always_run: true 18 | decorate: true 19 | clone_uri: "https://github.com/kcp-dev/api-syncagent" 20 | labels: 21 | preset-goproxy: "true" 22 | spec: 23 | containers: 24 | - image: ghcr.io/kcp-dev/infra/build:1.24.3-1 25 | command: 26 | - hack/ci/verify.sh 27 | resources: 28 | requests: 29 | memory: 1Gi 30 | cpu: 1 31 | 32 | - name: pull-api-syncagent-lint 33 | always_run: true 34 | decorate: true 35 | clone_uri: "https://github.com/kcp-dev/api-syncagent" 36 | labels: 37 | preset-goproxy: "true" 38 | spec: 39 | containers: 40 | - image: ghcr.io/kcp-dev/infra/build:1.24.3-1 41 | command: 42 | - make 43 | - lint 44 | resources: 45 | requests: 46 | memory: 4Gi 47 | cpu: 2 48 | 49 | - name: pull-api-syncagent-build-image 50 | always_run: true 51 | decorate: true 52 | clone_uri: "https://github.com/kcp-dev/api-syncagent" 53 | labels: 54 | preset-goproxy: "true" 55 | spec: 56 | containers: 57 | - image: quay.io/containers/buildah:v1.38.0 58 | command: 59 | - hack/ci/build-image.sh 60 | env: 61 | - name: DRY_RUN 62 | value: '1' 63 | # docker-in-docker needs privileged mode 64 | securityContext: 65 | privileged: true 66 | resources: 67 | requests: 68 | memory: 1Gi 69 | cpu: 1 70 | 71 | - name: pull-api-syncagent-test 72 | always_run: true 73 | decorate: true 74 | clone_uri: "https://github.com/kcp-dev/api-syncagent" 75 | labels: 76 | preset-goproxy: "true" 77 | spec: 78 | containers: 79 | - image: ghcr.io/kcp-dev/infra/build:1.24.3-1 80 | command: 81 | - make 82 | - test 83 | env: 84 | - name: USE_GOTESTSUM 85 | value: '1' 86 | resources: 87 | requests: 88 | memory: 4Gi 89 | cpu: 2 90 | 91 | - name: pull-api-syncagent-test-e2e 92 | always_run: true 93 | decorate: true 94 | clone_uri: "https://github.com/kcp-dev/api-syncagent" 95 | labels: 96 | preset-goproxy: "true" 97 | spec: 98 | containers: 99 | - image: ghcr.io/kcp-dev/infra/build:1.24.3-1 100 | command: 101 | - hack/ci/run-e2e-tests.sh 102 | resources: 103 | requests: 104 | memory: 4Gi 105 | cpu: 2 106 | # docker-in-docker needs privileged mode 107 | securityContext: 108 | privileged: true 109 | -------------------------------------------------------------------------------- /.wwhrd.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # To add a license, we follow https://github.com/cncf/foundation/blob/main/allowed-third-party-license-policy.md. 16 | 17 | denylist: 18 | - GPL-2.0 19 | - LGPL-3.0 20 | 21 | allowlist: 22 | - Apache-2.0 23 | - MIT 24 | - BSD-2-Clause 25 | - BSD-2-Clause-FreeBSD 26 | - BSD-3-Clause 27 | - ISC 28 | 29 | exceptions: 30 | - github.com/hashicorp/golang-lru/v2 # MPL 2.0 31 | - github.com/hashicorp/golang-lru/v2/internal # MPL 2.0 32 | - github.com/hashicorp/golang-lru/v2/simplelru # MPL 2.0 33 | - github.com/hashicorp/hcl # MPL 2.0 34 | - github.com/hashicorp/hcl/hcl/ast # MPL 2.0 35 | - github.com/hashicorp/hcl/hcl/parser # MPL 2.0 36 | - github.com/hashicorp/hcl/hcl/printer # MPL 2.0 37 | - github.com/hashicorp/hcl/hcl/scanner # MPL 2.0 38 | - github.com/hashicorp/hcl/hcl/strconv # MPL 2.0 39 | - github.com/hashicorp/hcl/hcl/token # MPL 2.0 40 | - github.com/hashicorp/hcl/json/parser # MPL 2.0 41 | - github.com/hashicorp/hcl/json/scanner # MPL 2.0 42 | - github.com/hashicorp/hcl/json/token # MPL 2.0 43 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to kcp 2 | 3 | We're thrilled that you're interested in contributing to kcp! Please visit our 4 | [full contributing guide](https://docs.kcp.io/kcp/main/en/CONTRIBUTING/) on our documentation site. 5 | 6 | Beside that, what coverns the project and all contributions to it must follow 7 | the [kcp Project Governance](./GOVERNANCE.md). 8 | 9 | From the kcp Project Governance, the following manifesto should guide the technical 10 | decisions through-out all contributions: 11 | 12 | > kcp maintainers strive to be good citizens in the Kubernetes project. 13 | > kcp maintainers see kcp always as part of the Kubernetes ecosystem and always strive to keep that ecosystem united. In particular, this means: 14 | > - kcp strives to not divert from Kubernetes, but strives to extend its use-cases to non-container control planes while keeping the ecosystems of libraries and tooling united. 15 | > - kcp – as a consumer of Kubernetes API Machinery – will strive to stay 100% compatible with the semantics of Kubernetes APIs, while removing container orchestration specific functionality. 16 | > - kcp strives to upstream changes to Kubernetes code as much as possible. 17 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this 7 | license document, but changing it is not allowed. 8 | 9 | 10 | Developer's Certificate of Origin 1.1 11 | 12 | By making a contribution to this project, I certify that: 13 | 14 | (a) The contribution was created in whole or in part by me and I 15 | have the right to submit it under the open source license 16 | indicated in the file; or 17 | 18 | (b) The contribution is based upon previous work that, to the best 19 | of my knowledge, is covered under an appropriate open source 20 | license and I have the right under that license to submit that 21 | work with modifications, whether created in whole or in part 22 | by me, under the same open source license (unless I am 23 | permitted to submit under a different license), as indicated 24 | in the file; or 25 | 26 | (c) The contribution was provided directly to me by some other 27 | person who certified (a), (b) or (c) and I have not modified 28 | it. 29 | 30 | (d) I understand and agree that this project and the contribution 31 | are public and that a record of the contribution (including all 32 | personal information I submit with it, including my sign-off) is 33 | maintained indefinitely and may be redistributed consistent with 34 | this project or the open source license(s) involved. 35 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM --platform=${BUILDPLATFORM} docker.io/golang:1.24.3 AS builder 16 | ARG TARGETOS 17 | ARG TARGETARCH 18 | 19 | WORKDIR /go/src/github.com/kcp-dev/api-syncagent 20 | COPY . . 21 | RUN GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} make clean api-syncagent 22 | 23 | FROM gcr.io/distroless/static-debian12:debug 24 | LABEL org.opencontainers.image.source=https://github.com/kcp-dev/api-syncagent 25 | LABEL org.opencontainers.image.description="A Kubernetes agent to synchronize APIs and their objects between Kubernetes clusters and kcp" 26 | LABEL org.opencontainers.image.licenses=Apache-2.0 27 | 28 | COPY --from=builder /go/src/github.com/kcp-dev/api-syncagent/_build/api-syncagent /usr/local/bin/api-syncagent 29 | 30 | USER nobody 31 | ENTRYPOINT [ "api-syncagent" ] 32 | -------------------------------------------------------------------------------- /GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # kcp Project Governance 2 | 3 | The kcp project is dedicated to democratizing Control Planes beyond container 4 | orchestration. Our project governance is explained [here](https://github.com/kcp-dev/kcp/blob/main/GOVERNANCE.md). 5 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md 2 | 3 | approvers: 4 | - embik 5 | - xrstf 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kcp API Sync Agent 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/kcp-dev/api-syncagent)](https://goreportcard.com/report/github.com/kcp-dev/api-syncagent) 4 | [![GitHub](https://img.shields.io/github/license/kcp-dev/api-syncagent)](https://img.shields.io/github/license/kcp-dev/api-syncagent) 5 | [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/kcp-dev/api-syncagent?sort=semver)](https://img.shields.io/github/v/release/kcp-dev/api-syncagent?sort=semver) 6 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkcp-dev%2Fapi-syncagent.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkcp-dev%2Fapi-syncagent?ref=badge_shield) 7 | 8 | The kcp API Sync Agent is a Kubernetes controller capable of synchronizing objects from many kcp 9 | workspaces onto a single Kubernetes cluster (with kcp being the source of truth). In doing so it will 10 | move the desired state (usually the spec) of an object from kcp to the local cluster where the agent 11 | is running, and move the current object status back up into kcp. The agent can also sync so-called 12 | related objects, like a Secret belonging to a Certificate, in both directions. 13 | 14 | The agent can be used to provide an API in kcp and then serving it from a remote Kubernetes cluster 15 | where the actual workload is then processed, usually by a 3rd-party operator. In many situations the 16 | synchronized objects are further processed using tools like Crossplane. 17 | 18 | ## Documentation 19 | 20 | Please visit [https://docs.kcp.io/api-syncagent](https://docs.kcp.io/api-syncagent) for the latest 21 | documentation. 22 | 23 | ## Troubleshooting 24 | 25 | If you encounter problems, please [file an issue][1]. 26 | 27 | ## Contributing 28 | 29 | Thanks for taking the time to start contributing! 30 | 31 | ### Before you start 32 | 33 | * Please familiarize yourself with the [Code of Conduct][4] before contributing. 34 | * See [CONTRIBUTING.md][2] for instructions on the developer certificate of origin that we require. 35 | 36 | ### Pull requests 37 | 38 | * We welcome pull requests. Feel free to dig through the [issues][1] and jump in. 39 | 40 | ## Changelog 41 | 42 | See [the list of releases][3] to find out about feature changes. 43 | 44 | ## License 45 | 46 | Apache 2.0 47 | 48 | [1]: https://github.com/kcp-dev/api-syncagent/issues 49 | [2]: https://github.com/kcp-dev/api-syncagent/blob/main/CONTRIBUTING.md 50 | [3]: https://github.com/kcp-dev/api-syncagent/releases 51 | [4]: https://github.com/kcp-dev/api-syncagent/blob/main/CODE_OF_CONDUCT.md 52 | -------------------------------------------------------------------------------- /cmd/crd-puller/.gitignore: -------------------------------------------------------------------------------- 1 | /crd-puller 2 | *.yaml 3 | -------------------------------------------------------------------------------- /cmd/crd-puller/README.md: -------------------------------------------------------------------------------- 1 | # CRD Puller 2 | 3 | The `crd-puller` can be used for testing and development in order to export a 4 | CustomResourceDefinition for any Group/Kind (GK) in a Kubernetes cluster. 5 | 6 | The main difference between this and kcp's own `crd-puller` is that this one 7 | works based on GKs and not resources (i.e. on `apps/Deployment` instead of 8 | `apps.deployments`). This is more useful since a PublishedResource publishes a 9 | specific Kind and version. Also, this puller pulls all available versions, not 10 | just the preferred version. 11 | 12 | ## Usage 13 | 14 | ```shell 15 | export KUBECONFIG=/path/to/kubeconfig 16 | 17 | ./crd-puller Deployment.apps.k8s.io 18 | ``` 19 | -------------------------------------------------------------------------------- /cmd/crd-puller/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | 24 | "github.com/spf13/pflag" 25 | 26 | "github.com/kcp-dev/api-syncagent/internal/discovery" 27 | 28 | "k8s.io/apimachinery/pkg/runtime/schema" 29 | "k8s.io/client-go/tools/clientcmd" 30 | "sigs.k8s.io/yaml" 31 | ) 32 | 33 | var ( 34 | kubeconfigPath string 35 | ) 36 | 37 | func main() { 38 | ctx := context.Background() 39 | 40 | pflag.StringVar(&kubeconfigPath, "kubeconfig", "", "Path to the kubeconfig file to use (defaults to $KUBECONFIG)") 41 | pflag.Parse() 42 | 43 | if pflag.NArg() == 0 { 44 | log.Fatal("No argument given. Please specify a GroupKind in the form 'Kind.apigroup.com' (case-sensitive) to pull.") 45 | } 46 | 47 | gk := schema.ParseGroupKind(pflag.Arg(0)) 48 | 49 | loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() 50 | loadingRules.ExplicitPath = kubeconfigPath 51 | 52 | startingConfig, err := loadingRules.GetStartingConfig() 53 | if err != nil { 54 | log.Fatalf("Failed to load Kubernetes configuration: %v.", err) 55 | } 56 | 57 | config, err := clientcmd.NewDefaultClientConfig(*startingConfig, nil).ClientConfig() 58 | if err != nil { 59 | log.Fatalf("Failed to load Kubernetes configuration: %v.", err) 60 | } 61 | 62 | discoveryClient, err := discovery.NewClient(config) 63 | if err != nil { 64 | log.Fatalf("Failed to create discovery client: %v.", err) 65 | } 66 | 67 | crd, err := discoveryClient.RetrieveCRD(ctx, gk) 68 | if err != nil { 69 | log.Fatalf("Failed to pull CRD: %v.", err) 70 | } 71 | 72 | enc, err := yaml.Marshal(crd) 73 | if err != nil { 74 | log.Fatalf("Failed to encode CRD as YAML: %v.", err) 75 | } 76 | 77 | fmt.Println(string(enc)) 78 | } 79 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | generated 3 | __pycache__ 4 | -------------------------------------------------------------------------------- /docs/content/.pages: -------------------------------------------------------------------------------- 1 | nav: 2 | - Home: README.md 3 | - Getting Started: getting-started.md 4 | - Publishing Resources: publish-resources 5 | - Consuming Services: consuming-services.md 6 | - FAQ: faq.md 7 | - Reference: reference 8 | - Contributing: contributing 9 | -------------------------------------------------------------------------------- /docs/content/consuming-services.md: -------------------------------------------------------------------------------- 1 | # Consuming Services 2 | 3 | This document describes how to use (consume) services offered by a Sync Agent. 4 | 5 | ## Background 6 | 7 | A "service" defines a unique Kubernetes API Group and offers a number of resources (types) to 8 | use. A service could offer certificate management, databases, cloud infrastructure or any other set 9 | of Kubernetes resources. 10 | 11 | Services are provided by service owners, who run their own Kubernetes clusters and take care of the 12 | maintenance and scaling tasks for the workload provisioned by all users of the service(s) they 13 | offer. 14 | 15 | A Service provided by a Sync Agent should not be confused with a Kubernetes Service. Internally, a 16 | "Sync Agent Service" is ultimately translated into a kcp `APIExport` with a number of 17 | `APIResourceSchemas` (which are more or less equivalent to CRDs). 18 | 19 | ## Consuming a Service 20 | 21 | To consume a service (or to make use of an `APIExport`) you have to create an `APIBinding` object 22 | in the kcp workspace where the service should be used. This section assumes that you are familiar 23 | with kcp on the command line and have the kcp kubectl plugin installed. 24 | 25 | First you need to get the kubeconfig for accessing your kcp workspaces. Once you have set your 26 | kubeconfig up, make sure you're in the correct namespace by using 27 | `kubectl ws `. Use `kubectl ws .` if you're unsure where you're at. 28 | 29 | To enable a Service, use `kcp bind apiexport` and specify the path to and name of the `APIExport`. 30 | 31 | ```bash 32 | # kubectl kcp bind apiexport : 33 | kubectl kcp bind apiexport :root:my-org:my.fancy.api 34 | ``` 35 | 36 | Without the plugin, you can create an `APIBinding` manually, simply `kubectl apply` this: 37 | 38 | ```yaml 39 | apiVersion: apis.kcp.io/v1alpha1 40 | kind: APIBinding 41 | metadata: 42 | name: my.fancy.api 43 | spec: 44 | reference: 45 | export: 46 | name: my.fancy.api 47 | path: root:my-org 48 | ``` 49 | 50 | Shortly after, the new API will be available in the workspace. Check via `kubectl api-resources`. 51 | You can now create objects for types in that API group to your liking and they will be synced and 52 | processed behind the scenes. 53 | 54 | Note that a Service often has related resources, often Secrets and ConfigMaps. You must explicitly 55 | allow the Service to access these in your workspace and this means editing/patching the `APIBinding` 56 | object (the kcp kubectl plugin currently has no support for managing permission claims). For each of 57 | the claimed resources, you have to accept or reject them: 58 | 59 | ```yaml 60 | spec: 61 | permissionClaims: 62 | # Nearly all Sync Agents require access to namespaces, rejecting this will 63 | # most likely break the Service, even more than rejecting any other claim. 64 | - all: true 65 | resources: namespaces 66 | state: Accepted 67 | - all: true 68 | resources: secrets 69 | state: Accepted # or Rejected 70 | ``` 71 | 72 | Rejecting a claim will severely impact a Service, if not even break it. Consult with the Service's 73 | documentation or the service owner if rejecting a claim is supported. 74 | 75 | When you _change into_ (`kubctl ws …`) a different workspace, kubectl will inform you if there are 76 | outstanding permission claims that you need to accept or reject. 77 | -------------------------------------------------------------------------------- /docs/content/contributing/releasing.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | The guide describes how to release a new version of the api-syncagent. 4 | 5 | ## Prerequisites 6 | 7 | 1. Have all desired changes merged and/or cherrypicked into the appropriate 8 | release branch. 9 | 10 | ## Minor Release 11 | 12 | Minor releases (0.x) are tagged directly on the `main` branch and the `v0.X.0` 13 | tag represents where the corresponding `release/v0.X` branch branches off. 14 | 15 | 1. Checkout the desired `main` branch commit. 16 | 1. Tag the main module: `git tag -m "version 0.X" v0.X.0` 17 | 1. Tag the SDK module: `git tag -m "SDK version 0.X" sdk/v0.X.0` 18 | 1. Push the tags: `git push upstream v0.X.0 sdk/v0.X.0` 19 | 1. Create the release branch: `git checkout -B release/v0.X` 20 | 1. Push the release branch: `git push -u upstream release/v0.X` 21 | 22 | ## Patch Releases 23 | 24 | Patch releases (v0.x.y) are tagged with in a release branch. 25 | 26 | 1. Checkout the desired `release/v0.X` branch commit. 27 | 1. Tag the main module: `git tag -m "version 0.X.Y" v0.X.Y` 28 | 1. Tag the SDK module: `git tag -m "SDK version 0.X.Y" sdk/v0.X.Y` 29 | 1. Push the tags: `git push upstream v0.X.Y sdk/v0.X.Y` 30 | -------------------------------------------------------------------------------- /docs/content/faq.md: -------------------------------------------------------------------------------- 1 | # Frequently Asked Questions 2 | 3 | ## Can I run multiple Sync Agents on the same service cluster? 4 | 5 | Yes, absolutely, however you must configure them properly: 6 | 7 | A given `PublishedResource` must only ever be processed by a single Sync Agent Pod. The Helm chart 8 | configures leader-election by default, so you can scale up to have Pods on stand-by if needed. 9 | 10 | By default the Sync Agent will discover and process all `PublishedResources` in your cluster. Use 11 | the `--published-resource-selector` (`publishedResourceSelector` in the Helm values.yaml) to 12 | restrict an Agent to a subset of published resources. 13 | 14 | ## Can I synchronize multiple kcp setups onto the same service cluster? 15 | 16 | Only if you have distinct API groups (and therefore also distinct `PublishedResources`) for them. 17 | You cannot currently publish the same API group onto multiple kcp setups. See issue #13 for more 18 | information. 19 | 20 | ## Can I have additional resources in APIExports, unmanaged by the Sync Agent? 21 | 22 | Yes, you can. The agent will only ever change those resourceSchemas that match group/resource of 23 | the configured `PublishedResources`. So if you configure the agent to publish 24 | `cert-manager.io/Certificate`, this would "claim" all resource schemas ending in 25 | `.certificates.cert-manager.io`. When updating the `APIExport`, the agent will only touch schemas 26 | with this suffix and leave all others alone. 27 | 28 | This is also used when a `PublishedResource` is deleted: Since the `APIResourceSchema` remains in kcp, 29 | but is no longer configured in the agent, the agent will simply ignore the schema in the `APIExport`. 30 | This allows for async cleanup processes to happen before an admin ultimately removes the old 31 | schema from the `APIExport`. 32 | 33 | ## Does the Sync Agent handle permission claims? 34 | 35 | Only those required for its own operation. If you configure a namespaced resource to sync, it will 36 | automatically add a claim for `namespaces` in kcp, plus it will add either `configmaps` or `secrets` 37 | if related resources are configured in a `PublishedResource`. But you cannot specify additional 38 | permissions claims. 39 | 40 | ## I am seeing errors in the agent logs, what's going on? 41 | 42 | Errors like 43 | 44 | > reflector.go:561] k8s.io/client-go@v0.31.2/tools/cache/reflector.go:243: failed to list 45 | > example.com/v1, Kind=Dummy: the server could not find the requested resource 46 | 47 | or 48 | 49 | > reflector.go:158] "Unhandled Error" err="k8s.io/client-go@v0.31.2/tools/cache/reflector.go:243: 50 | > Failed to watch kcp.example.com/v1, Kind=Dummy: failed to list kcp.example.com/v1, Kind=Dummy: 51 | > the server could not find the requested resource" logger="UnhandledError" 52 | 53 | are typical when bootstrapping new APIExports in kcp. They are only cause for concern if they 54 | persist after configuring all PublishedResources. 55 | -------------------------------------------------------------------------------- /docs/content/publish-resources/.pages: -------------------------------------------------------------------------------- 1 | nav: 2 | - index.md 3 | - templating.md 4 | - api-lifecycle.md 5 | - technical-details.md 6 | -------------------------------------------------------------------------------- /docs/content/reference/.gitignore: -------------------------------------------------------------------------------- 1 | crd/ 2 | -------------------------------------------------------------------------------- /docs/content/reference/.pages: -------------------------------------------------------------------------------- 1 | nav: 2 | - index.md 3 | - CRD: crd 4 | -------------------------------------------------------------------------------- /docs/content/reference/index.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | This chapter provides automatically generated references for the APIs provided by the kcp Sync Agent. 4 | -------------------------------------------------------------------------------- /docs/generators/crd-ref/config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | template_path: ./crd.template.md 16 | 17 | source_repositories: 18 | - url: https://github.com/kcp-dev/api-syncagent 19 | organization: kcp-dev 20 | short_name: api-syncagent 21 | commit_reference: main 22 | crd_paths: 23 | - deploy/crd 24 | cr_paths: 25 | - docs/cr 26 | metadata: 27 | publishedresources.syncagent.kcp.io: 28 | owner: 29 | - https://github.com/kcp-dev/api-syncagent 30 | -------------------------------------------------------------------------------- /docs/generators/crd-ref/run-crd-ref-gen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2021 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd) 20 | 21 | CONTAINER_ENGINE=${CONTAINER_ENGINE:-podman} 22 | CRD_DOCS_GENERATOR_VERSION=0.11.4 23 | 24 | DESTINATION="${REPO_ROOT}/docs/content/reference/crd" 25 | mkdir -p "${DESTINATION}" 26 | 27 | BIND_MOUNT_OPTS=":z" 28 | if [[ $(uname -s) == "Darwin" ]]; then 29 | BIND_MOUNT_OPTS="" 30 | fi 31 | 32 | # Generate new content 33 | $CONTAINER_ENGINE run \ 34 | --rm \ 35 | -v "${DESTINATION}":/opt/crd-docs-generator/output"${BIND_MOUNT_OPTS}" \ 36 | -v "${REPO_ROOT}"/docs/generators/crd-ref:/opt/crd-docs-generator/config"${BIND_MOUNT_OPTS}" \ 37 | "quay.io/giantswarm/crd-docs-generator:${CRD_DOCS_GENERATOR_VERSION}" \ 38 | --config /opt/crd-docs-generator/config/config.yaml 39 | 40 | # Organise CRDs by API group 41 | for file in ${DESTINATION}/*.md; do 42 | filename="$(basename $file)" 43 | apigroup="$(basename $filename .md | cut -d. -f2-)" 44 | crdname="$(basename $filename .md | cut -d. -f1)" 45 | 46 | mkdir -p "${DESTINATION}/${apigroup}" 47 | mv "${file}" "${DESTINATION}/${apigroup}/${crdname}.md" 48 | done 49 | 50 | # Generate a .pages config file to override title case being applied to 51 | # folder names by default (https://github.com/mkdocs/mkdocs/issues/2086) 52 | echo "nav:" > "${DESTINATION}/.pages" 53 | for dir in ${DESTINATION}/*/; do 54 | apigroup="$(basename $dir)" 55 | echo " - ${apigroup}: ${apigroup}" >> "${DESTINATION}/.pages" 56 | done 57 | -------------------------------------------------------------------------------- /docs/main.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import copy 16 | 17 | def define_env(env): 18 | """ 19 | This is the hook for defining variables, macros, and filters. See 20 | https://mkdocs-macros-plugin.readthedocs.io/en/latest/macros/#the-define_env-function for more details. 21 | 22 | :param env: the Jinja2 environment 23 | """ 24 | 25 | @env.macro 26 | def section_items(page, nav, config): 27 | """ 28 | Returns a list of all pages that are siblings to page. 29 | 30 | :param page: the current page. This will typically be an index.md page. 31 | :param nav: the mkdocs navigation object. 32 | :param config: the mkdocs config object. 33 | :return: a list of all the sibling pages. 34 | """ 35 | 36 | if page.parent: 37 | children = page.parent.children 38 | else: 39 | children = nav.items 40 | 41 | siblings = [] 42 | for child in children: 43 | if child is page: 44 | # don't include the passed in page in the list 45 | continue 46 | if child.is_section: 47 | # don't include sections 48 | continue 49 | if child.file.name == 'index': 50 | # don't include index pages 51 | continue 52 | 53 | # Because some pages might not have been loaded yet, we have to do so now, to get title/metadata. 54 | child.read_source(config) 55 | 56 | # Copy so we don't modify the original 57 | child = copy.deepcopy(child) 58 | 59 | # Subsection nesting that works across any level of nesting 60 | # Replaced mkdocs fix_url function 61 | child.file.url = child.url.replace(page.url, "./") 62 | siblings.append(child) 63 | 64 | return siblings 65 | -------------------------------------------------------------------------------- /docs/overrides/favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/overrides/favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/overrides/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/overrides/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/overrides/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/overrides/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/favicon.ico -------------------------------------------------------------------------------- /docs/overrides/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kcp-dev/api-syncagent/1b5392efdcf506cc5148025a8a2b56a9fc0d8c9a/docs/overrides/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /docs/overrides/partials/outdated.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block outdated %} 3 | You're not viewing the latest version. 4 | 5 | Click here to go to latest. 6 | 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /docs/overrides/partials/section-overview.html: -------------------------------------------------------------------------------- 1 | {% for item in section_items(page, navigation, config) %} 2 | ### [{{ item.title }}]({{ item.file.url }}) 3 | {{ item.meta.description or '' }} 4 | {% endfor %} 5 | -------------------------------------------------------------------------------- /docs/overrides/stylesheets/crd.css: -------------------------------------------------------------------------------- 1 | /* Taken from https://github.com/giantswarm/docs/blob/main/src/static/css/crd.css 2 | * Changes made: 3 | * - Change font-family to var(--md-code-font-family) and property colors to match theme. 4 | * - Adjust border colors to be more in line with material theme. 5 | * - Add dark theme variants for crd-meta elements. 6 | * - Add padding to crd-meta. 7 | */ 8 | 9 | /* Styles for the CRD schema reference documentation */ 10 | 11 | ul.crd-index { 12 | margin-top: 2em; 13 | margin-bottom: 2em; 14 | } 15 | 16 | .crd-index .tag { 17 | background-color: #ccc; 18 | padding: 2px 7px; 19 | font-size: 14px; 20 | border-radius: 3px; 21 | } 22 | .crd-index .tag-provider { 23 | text-transform: uppercase; 24 | } 25 | .crd-index .tag-provider-aws { 26 | background-color: #ed9235; 27 | color: #232f3b; 28 | } 29 | .crd-index .tag-provider-azure { 30 | background-color: #1773bd; 31 | color: #fff; 32 | } 33 | .crd-index .tag-topic { 34 | background-color: #5eaebb; 35 | color: #fff; 36 | } 37 | 38 | 39 | dl.crd-meta { 40 | display: flex; 41 | flex-flow: row wrap; 42 | border-bottom: 1px solid #00000012; 43 | } 44 | 45 | [data-md-color-primary=black] dl.crd-meta { 46 | border-bottom: 1px solid #e6e6e612; 47 | } 48 | 49 | .crd-meta dt { 50 | flex-basis: 20%; 51 | margin: 0; 52 | padding: 8px 8px; 53 | border-top: 1px solid #00000012; 54 | font-weight: bold; 55 | } 56 | 57 | .crd-meta dd { 58 | flex-basis: 70%; 59 | flex-grow: 1; 60 | margin: 0; 61 | padding: 8px 8px; 62 | border-top: 1px solid #00000012; 63 | } 64 | 65 | [data-md-color-primary=black] .crd-meta dt, [data-md-color-primary=black] .crd-meta dd { 66 | border-top: 1px solid #e6e6e612; 67 | } 68 | 69 | .crd-meta a.version { 70 | font-family: var(--md-code-font-family); 71 | font-size: 72 | margin-right: 10px; 73 | } 74 | 75 | .property { 76 | margin-bottom: 1em; 77 | } 78 | 79 | .property-header h3 { 80 | font-family: var(--md-code-font-family); 81 | font-size: 22px; 82 | margin: 0; 83 | margin-left: -0.1em; 84 | } 85 | 86 | .property-description, .property-meta { 87 | margin: 5px 0 88 | } 89 | 90 | .property-title { 91 | font-style: italic; 92 | } 93 | 94 | .property-type { 95 | color: var(--md-code-fg-color); 96 | background-color: var(--md-code-bg-color); 97 | font-family: var(--md-code-font-family); 98 | font-size: 14px; 99 | line-height: 22px; 100 | padding: 3px 6px; 101 | text-transform: uppercase; 102 | } 103 | 104 | .property-required { 105 | background-color: var(--md-accent-fg-color); 106 | color: var(--md-accent-bg-color); 107 | font-size: 14px; 108 | line-height: 22px; 109 | padding: 3px 6px; 110 | text-transform: uppercase; 111 | } 112 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mike==2.1.3 2 | mkdocs==1.5.3 3 | mkdocs-awesome-pages-plugin==2.9.2 4 | mkdocs-macros-plugin==1.3.7 5 | mkdocs-material==9.5.17 6 | mkdocs-material-extensions==1.3.1 7 | mkdocs-static-i18n==1.2.2 8 | -------------------------------------------------------------------------------- /docs/scripts/deploy-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) 20 | cd "$REPO_ROOT/docs" 21 | 22 | if [[ "${GITHUB_EVENT_NAME:-}" == "pull_request" ]]; then 23 | # For PRs, we don't want to use GITHUB_REF_NAME, which will be something like merge/1234; instead, we want to use 24 | # the branch the PR is targeting, such as main or release-0.11 25 | VERSION=$GITHUB_BASE_REF 26 | else 27 | if [[ -n "${GITHUB_REF_NAME:-}" ]]; then 28 | VERSION="${VERSION:-$GITHUB_REF_NAME}" 29 | else 30 | VERSION=${VERSION:-$(git rev-parse --abbrev-ref HEAD)} 31 | fi 32 | 33 | if echo "$VERSION" | grep '^release-[0-9]'; then 34 | VERSION=v$(echo "$VERSION" | cut -d - -f 2) 35 | elif echo "$VERSION" | grep '^v[0-9]\+\.[0-9]\+'; then 36 | VERSION=$(echo "$VERSION" | grep -o '^v[0-9]\+\.[0-9]\+') 37 | fi 38 | fi 39 | 40 | MIKE_OPTIONS=() 41 | MIKE_DEPLOY_OPTIONS=() 42 | MIKE_ALIASES=() 43 | 44 | if [[ -n "${REMOTE:-}" ]]; then 45 | MIKE_OPTIONS+=(--remote "$REMOTE") 46 | fi 47 | 48 | if [[ -n "${BRANCH:-}" ]]; then 49 | MIKE_OPTIONS+=(--branch "$BRANCH") 50 | fi 51 | 52 | LATEST=$(git describe --tags --match="v[0-9]*" `git rev-list --tags --max-count=1` | grep -o '^v[0-9]\+\.[0-9]\+') 53 | if [[ "${LATEST:-}" == "${VERSION:-}" ]]; then 54 | MIKE_DEPLOY_OPTIONS+=(--update-aliases) 55 | MIKE_ALIASES+=(latest) 56 | fi 57 | 58 | if [[ -n "${CI:-}" ]]; then 59 | if [[ "${GITHUB_EVENT_NAME:-}" == "push" ]] || [[ "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" ]]; then 60 | # Only push to gh-pages if we're in GitHub Actions (CI is set) and we have a non-PR event. 61 | MIKE_OPTIONS+=(--push) 62 | fi 63 | 64 | # Always set git user info in CI because even if we're not pushing, we need it 65 | git config user.name kcp-ci-bot 66 | git config user.email no-reply@kcp.io 67 | else 68 | MIKE_OPTIONS+=(--ignore-remote-status) 69 | fi 70 | 71 | mike deploy "${MIKE_OPTIONS[@]}" "${MIKE_DEPLOY_OPTIONS[@]}" "$VERSION" "${MIKE_ALIASES[@]}" 72 | 73 | if [[ -n "${CI:-}" ]]; then 74 | if [[ "${GITHUB_EVENT_NAME:-}" == "push" ]] || [[ "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" ]]; then 75 | if [[ "${LATEST:-}" == "${VERSION:-}" ]]; then 76 | # only set the default if we pushed before, otherwise the "latest" alias might not yet exist. 77 | mike set-default "${MIKE_OPTIONS[@]}" latest 78 | fi 79 | fi 80 | fi 81 | -------------------------------------------------------------------------------- /docs/scripts/serve-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) 22 | cd "$REPO_ROOT/docs" 23 | 24 | MIKE_OPTIONS=() 25 | 26 | if [[ -n "${REMOTE:-}" ]]; then 27 | MIKE_OPTIONS+=(--remote "$REMOTE") 28 | fi 29 | 30 | if [[ -n "${BRANCH:-}" ]]; then 31 | MIKE_OPTIONS+=(--branch "$BRANCH") 32 | fi 33 | 34 | # for local docs testing, we don't care what the remote branch looks like. 35 | MIKE_OPTIONS+=(--ignore-remote-status) 36 | 37 | mike set-default "${MIKE_OPTIONS[@]}" --allow-undefined main 38 | mike serve "${MIKE_OPTIONS[@]}" 39 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.Dockerfile.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright YEAR The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.sh.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.yaml.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.yml.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hack/boilerplate/generated/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /hack/ci/run-e2e-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | source hack/lib.sh 19 | 20 | # have a place to store things 21 | if [ -z "${ARTIFACTS:-}" ]; then 22 | ARTIFACTS=.e2e/artifacts 23 | mkdir -p "$ARTIFACTS" 24 | fi 25 | 26 | echodate "Build artifacts will be placed in $ARTIFACTS." 27 | export ARTIFACTS="$(realpath "$ARTIFACTS")" 28 | 29 | # build the agent, we will start it many times during the tests 30 | echodate "Building the api-syncagent…" 31 | make build 32 | 33 | # get kube envtest binaries 34 | echodate "Setting up Kube binaries…" 35 | make _tools/setup-envtest 36 | export KUBEBUILDER_ASSETS="$(_tools/setup-envtest use 1.31.0 --bin-dir _tools -p path)" 37 | KUBEBUILDER_ASSETS="$(realpath "$KUBEBUILDER_ASSETS")" 38 | 39 | # start a shared kcp process 40 | make _tools/kcp 41 | 42 | KCP_ROOT_DIRECTORY=.kcp.e2e 43 | KCP_LOGFILE="$ARTIFACTS/kcp.log" 44 | KCP_TOKENFILE=hack/ci/testdata/e2e-kcp.tokens 45 | 46 | echodate "Starting kcp…" 47 | rm -rf "$KCP_ROOT_DIRECTORY" "$KCP_LOGFILE" 48 | _tools/kcp start \ 49 | -v4 \ 50 | --token-auth-file "$KCP_TOKENFILE" \ 51 | --root-directory "$KCP_ROOT_DIRECTORY" 1>"$KCP_LOGFILE" 2>&1 & 52 | 53 | stop_kcp() { 54 | echodate "Stopping kcp processes (set \$KEEP_KCP=true to not do this)…" 55 | pkill -e kcp 56 | } 57 | 58 | if [[ -v KEEP_KCP ]] && $KEEP_KCP; then 59 | echodate "\$KEEP_KCP is set, will not stop kcp once the script is finished." 60 | else 61 | append_trap stop_kcp EXIT 62 | fi 63 | 64 | # make the token available to the Go tests 65 | export KCP_AGENT_TOKEN="$(grep e2e "$KCP_TOKENFILE" | cut -f1 -d,)" 66 | 67 | # Wait for kcp to be ready; this env name is also hardcoded in the Go tests. 68 | export KCP_KUBECONFIG="$KCP_ROOT_DIRECTORY/admin.kubeconfig" 69 | 70 | # the tenancy API becomes available pretty late during startup, so it's a good readiness check 71 | if ! retry_linear 3 20 kubectl --kubeconfig "$KCP_KUBECONFIG" get workspaces; then 72 | echodate "kcp never became ready." 73 | exit 1 74 | fi 75 | 76 | # makes it easier to reference thesefiles from various _test.go files. 77 | export ROOT_DIRECTORY="$(realpath .)" 78 | export KCP_KUBECONFIG="$(realpath "$KCP_KUBECONFIG")" 79 | export AGENT_BINARY="$(realpath _build/api-syncagent)" 80 | 81 | # time to run the tests 82 | echodate "Running e2e tests…" 83 | WHAT="${WHAT:-./test/e2e/...}" 84 | (set -x; go test -tags e2e -timeout 2h -v $WHAT) 85 | 86 | echodate "Done. :-)" 87 | -------------------------------------------------------------------------------- /hack/ci/testdata/e2e-kcp.tokens: -------------------------------------------------------------------------------- 1 | topphemmelig,api-syncagent-e2e,1111-2222-3333-4444,"api-syncagents" 2 | -------------------------------------------------------------------------------- /hack/ci/verify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/../.. 20 | source hack/lib.sh 21 | 22 | EXIT_CODE=0 23 | SUMMARY= 24 | 25 | try() { 26 | local title="$1" 27 | shift 28 | 29 | heading "$title" 30 | echo 31 | 32 | start_time=$(date +%s) 33 | 34 | set +e 35 | $@ 36 | exitCode=$? 37 | set -e 38 | 39 | elapsed_time=$(($(date +%s) - $start_time)) 40 | TEST_NAME="$title" write_junit $exitCode "$elapsed_time" 41 | 42 | local status 43 | if [[ $exitCode -eq 0 ]]; then 44 | echo -e "\n[${elapsed_time}s] SUCCESS :)" 45 | status=OK 46 | else 47 | echo -e "\n[${elapsed_time}s] FAILED." 48 | status=FAIL 49 | EXIT_CODE=1 50 | fi 51 | 52 | SUMMARY="$SUMMARY\n$(printf "%-35s %s" "$title" "$status")" 53 | 54 | git reset --hard --quiet 55 | git clean --force 56 | 57 | echo 58 | } 59 | 60 | verify_codegen() { 61 | make codegen 62 | 63 | echo "Diffing…" 64 | if ! git diff --exit-code deploy internal sdk; then 65 | echo "The generated code / CRDs are out of date. Please run 'make codegen'." 66 | return 1 67 | fi 68 | 69 | echo "The generated code / CRDs is up to date." 70 | } 71 | 72 | verify_gomod() { 73 | go mod tidy 74 | go mod verify 75 | git diff --exit-code 76 | } 77 | 78 | verify_imports() { 79 | make imports 80 | 81 | echo "Diffing…" 82 | if ! git diff --exit-code; then 83 | echo "Some import statements are not properly grouped. Please run 'make imports'." 84 | return 1 85 | fi 86 | 87 | echo "Your Go import statements are in order :-)" 88 | } 89 | 90 | try "Verify code generation" verify_codegen 91 | try "Verify go.mod" verify_gomod 92 | try "Verify Go imports" verify_imports 93 | try "Verify license compatibility" ./hack/verify-licenses.sh 94 | try "Verify boilerplate" ./hack/verify-boilerplate.sh 95 | 96 | echo 97 | echo "SUMMARY" 98 | echo "=======" 99 | echo 100 | echo "Check Result" 101 | echo -n "------------------------------------------" 102 | echo -e "$SUMMARY" 103 | 104 | exit $EXIT_CODE 105 | -------------------------------------------------------------------------------- /hack/download-tool.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/.. 20 | 21 | mkdir -p _tools 22 | cd _tools 23 | 24 | URL="$1" 25 | BINARY="$2" 26 | VERSION="$3" 27 | BINARY_PATTERN="${4:-**/$BINARY}" 28 | GO_MODULE=${GO_MODULE:-false} 29 | UNCOMPRESSED=${UNCOMPRESSED:-false} 30 | 31 | # Check if and what version we installed already. 32 | versionFile="$BINARY.version" 33 | existingVersion="" 34 | if [ -f "$versionFile" ]; then 35 | existingVersion="$(cat "$versionFile")" 36 | fi 37 | 38 | # If the binary exists and its version matches, we're good. 39 | if [ -f "$BINARY" ] && [ "$VERSION" == "$existingVersion" ]; then 40 | exit 0 41 | fi 42 | 43 | ( 44 | rm -rf tmp 45 | mkdir -p tmp 46 | cd tmp 47 | 48 | echo "Downloading $BINARY version $VERSION …" >&2 49 | 50 | if $GO_MODULE; then 51 | GOBIN=$(realpath .) go install "$URL@$VERSION" 52 | mv * "../$BINARY" 53 | else 54 | curl --fail --silent -LO "$URL" 55 | archive="$(ls)" 56 | 57 | if ! $UNCOMPRESSED; then 58 | case "$archive" in 59 | *.tar.gz | *.tgz) 60 | tar xzf "$archive" 61 | ;; 62 | *.zip) 63 | unzip "$archive" 64 | ;; 65 | *) 66 | echo "Unknown file type: $archive" >&2 67 | exit 1 68 | esac 69 | fi 70 | 71 | mv $BINARY_PATTERN ../$BINARY 72 | chmod +x ../$BINARY 73 | fi 74 | ) 75 | 76 | rm -rf tmp 77 | echo "$VERSION" > "$versionFile" 78 | 79 | echo "Installed at _tools/$BINARY." >&2 80 | -------------------------------------------------------------------------------- /hack/reconciling.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The KCP Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This defines the reconciling helpers we generate using 16 | # https://github.com/kubermatic/reconciler 17 | 18 | package: reconciling 19 | boilerplate: hack/boilerplate/generated/boilerplate.go.txt 20 | resourceTypes: 21 | # kcp-dev/v1alpha1 22 | - { package: github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1, importAlias: kcpdevv1alpha1, resourceName: APIExport } 23 | - { package: github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1, importAlias: kcpdevv1alpha1, resourceName: APIResourceSchema } 24 | -------------------------------------------------------------------------------- /hack/run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/.. 20 | source hack/lib.sh 21 | 22 | CGO_ENABLED=1 go_test unit_tests \ 23 | -tags "unit" -timeout 20m -race -v ./... 24 | -------------------------------------------------------------------------------- /hack/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | 3 | /* 4 | Copyright 2025 The KCP Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package tools 20 | 21 | import ( 22 | _ "github.com/kcp-dev/code-generator/v2" 23 | _ "github.com/openshift-eng/openshift-goimports" 24 | _ "k8c.io/reconciler/cmd/reconciler-gen" 25 | 26 | _ "k8s.io/code-generator/cmd/applyconfiguration-gen" 27 | _ "k8s.io/code-generator/cmd/client-gen" 28 | _ "sigs.k8s.io/controller-tools/cmd/controller-gen" 29 | ) 30 | -------------------------------------------------------------------------------- /hack/update-codegen-crds.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/.. 20 | source hack/lib.sh 21 | 22 | mkdir -p _tools 23 | export GOBIN=$(realpath _tools) 24 | 25 | go install k8c.io/reconciler/cmd/reconciler-gen 26 | go install sigs.k8s.io/controller-tools/cmd/controller-gen 27 | 28 | echodate "Generating reconciling helpers…" 29 | 30 | reconcileHelpers=internal/resources/reconciling/zz_generated_reconcile.go 31 | $GOBIN/reconciler-gen --config hack/reconciling.yaml > $reconcileHelpers 32 | 33 | CRD_DIR=deploy/crd 34 | KCP_CRD_DIR="$CRD_DIR/kcp.io" 35 | rm -rf -- "$KCP_CRD_DIR" 36 | mkdir -p "$KCP_CRD_DIR" 37 | 38 | echodate "Generating openAPI v3 CRDs…" 39 | 40 | $GOBIN/controller-gen \ 41 | crd \ 42 | paths=./sdk/apis/... \ 43 | output:crd:dir=./$KCP_CRD_DIR 44 | 45 | # these are types only used for testing the syncer 46 | $GOBIN/controller-gen \ 47 | crd \ 48 | paths=./internal/sync/apis/... \ 49 | output:crd:dir=./internal/sync/crd/ 50 | 51 | beautify() { 52 | _tools/yq --inplace --no-doc 'del(.metadata.creationTimestamp)' "$1" 53 | 54 | mv "$1" "$1.bak" 55 | echo -e "# This file has been generated by hack/update-codegen-crds.sh, DO NOT EDIT.\n" > "$1" 56 | cat "$1.bak" >> "$1" 57 | rm "$1.bak" 58 | } 59 | 60 | # beautify CRDs just because we can 61 | for f in $KCP_CRD_DIR/*.yaml; do 62 | beautify "$f" 63 | done 64 | 65 | for f in internal/sync/crd/*.yaml; do 66 | beautify "$f" 67 | done 68 | -------------------------------------------------------------------------------- /hack/update-codegen-sdk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/.. 20 | source hack/lib.sh 21 | 22 | BOILERPLATE_HEADER="$(realpath hack/boilerplate/generated/boilerplate.go.txt)" 23 | SDK_MODULE="github.com/kcp-dev/api-syncagent/sdk" 24 | APIS_PKG="$SDK_MODULE/apis" 25 | 26 | mkdir -p _tools 27 | export GOBIN=$(realpath _tools) 28 | 29 | set -x 30 | 31 | go install k8s.io/code-generator/cmd/applyconfiguration-gen 32 | go install k8s.io/code-generator/cmd/client-gen 33 | go install github.com/kcp-dev/code-generator/v2 34 | go install github.com/openshift-eng/openshift-goimports 35 | go install sigs.k8s.io/controller-tools/cmd/controller-gen 36 | 37 | # these are types only used for testing the syncer 38 | $GOBIN/controller-gen \ 39 | "object:headerFile=$BOILERPLATE_HEADER" \ 40 | paths=./internal/sync/apis/... 41 | 42 | cd sdk 43 | rm -rf -- applyconfiguration clientset informers listers 44 | 45 | $GOBIN/controller-gen \ 46 | "object:headerFile=$BOILERPLATE_HEADER" \ 47 | paths=./apis/... 48 | 49 | $GOBIN/applyconfiguration-gen \ 50 | --go-header-file "$BOILERPLATE_HEADER" \ 51 | --output-dir applyconfiguration \ 52 | --output-pkg $SDK_MODULE/applyconfiguration \ 53 | ./apis/... 54 | 55 | $GOBIN/client-gen \ 56 | --go-header-file "$BOILERPLATE_HEADER" \ 57 | --output-dir clientset \ 58 | --output-pkg $SDK_MODULE/clientset \ 59 | --clientset-name versioned \ 60 | --input-base $APIS_PKG \ 61 | --input syncagent/v1alpha1 62 | 63 | $GOBIN/code-generator \ 64 | "client:headerFile=$BOILERPLATE_HEADER,apiPackagePath=$APIS_PKG,outputPackagePath=$SDK_MODULE,singleClusterClientPackagePath=$SDK_MODULE/clientset/versioned,singleClusterApplyConfigurationsPackagePath=applyconfiguration" \ 65 | "informer:headerFile=$BOILERPLATE_HEADER,apiPackagePath=$APIS_PKG,outputPackagePath=$SDK_MODULE,singleClusterClientPackagePath=$SDK_MODULE/clientset/versioned" \ 66 | "lister:headerFile=$BOILERPLATE_HEADER,apiPackagePath=$APIS_PKG" \ 67 | "paths=./apis/..." \ 68 | "output:dir=." 69 | 70 | # Use openshift's import fixer because gimps fails to parse some of the files; 71 | # its output is identical to how gimps would sort the imports, but it also fixes 72 | # the misplaced go:build directives. 73 | $GOBIN/openshift-goimports . 74 | -------------------------------------------------------------------------------- /hack/verify-boilerplate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/.. 20 | source hack/lib.sh 21 | 22 | make --no-print-directory _tools/boilerplate 23 | 24 | echo "Checking file boilerplates…" 25 | 26 | set -x 27 | 28 | _tools/boilerplate \ 29 | -boilerplates hack/boilerplate \ 30 | -exclude .github \ 31 | -exclude internal/certificates/triple \ 32 | -exclude sdk/applyconfiguration \ 33 | -exclude sdk/clientset \ 34 | -exclude sdk/informers \ 35 | -exclude sdk/listers \ 36 | -exclude test/crds 37 | 38 | _tools/boilerplate \ 39 | -boilerplates hack/boilerplate/generated \ 40 | sdk/applyconfiguration \ 41 | sdk/clientset \ 42 | sdk/informers \ 43 | sdk/listers 44 | -------------------------------------------------------------------------------- /hack/verify-licenses.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2025 The KCP Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | 19 | cd $(dirname $0)/.. 20 | source hack/lib.sh 21 | 22 | make --no-print-directory _tools/wwhrd 23 | 24 | go mod vendor 25 | 26 | echo "Checking licenses…" 27 | _tools/wwhrd check -q 28 | echo "Check successful." 29 | -------------------------------------------------------------------------------- /internal/controller/apiexport/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package apiexport contains a controller that watches for PublishedResources 19 | and then maintains a singular APIExport for all found PR's. The controller 20 | only includes PR's that already have an APIResourceSchema name attached, 21 | created by the accompanying controller in the Sync Agent. 22 | 23 | Note that for the time being, to prevent data loss, only new ARS will be added to 24 | the APIExport. Once an ARS is listed in the APIExport, it is supposed to remain 25 | until an administrator/other process performs garbage collection in kcp. 26 | */ 27 | package apiexport 28 | -------------------------------------------------------------------------------- /internal/controller/apiresourceschema/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package apiresourceschema contains a controller that watches for PublishedResources and CRDs 19 | and creates a matching APIResourceSchema (ARS) in kcp. 20 | The name of the generated ARS is stored in the PublishedResource's status, so that the 21 | apiexport controller can find and include it in the generated APIExport. 22 | 23 | The ARS name contains a hash over the Group, Kind and spec of the projected CRD. This way any 24 | changes to the original CRD or projection rules will result in a new ARS. 25 | 26 | There is no extra cleanup procedure in either of the clusters when a PublishedResource 27 | is deleted. This is to prevent accidental data loss in kcp in case a service owner 28 | accidentally (and temporarily) removed a PublishedResource. 29 | */ 30 | package apiresourceschema 31 | -------------------------------------------------------------------------------- /internal/controller/sync/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package sync contains a controller that watches the APIExport we manage in kcp. 19 | Once the virtual workspace URL for said APIExport is ready, the controller will 20 | begin to synchronize resources back and forth between kcp (i.e. all relevant 21 | workspaces) and the service cluster. 22 | */ 23 | package sync 24 | -------------------------------------------------------------------------------- /internal/controller/syncmanager/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package syncmanager contains a controller that watches the APIExport we manage 19 | in kcp. Once the virtual workspace URL for said APIExport is ready, the 20 | controller will begin to synchronize resources back and forth between kcp 21 | (i.e. all relevant workspaces) and the service cluster. 22 | */ 23 | package syncmanager 24 | -------------------------------------------------------------------------------- /internal/controller/syncmanager/lifecycle/controller.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package lifecycle 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | 23 | "go.uber.org/zap" 24 | 25 | "sigs.k8s.io/controller-runtime/pkg/controller" 26 | ) 27 | 28 | // Controller is a controller-runtime controller 29 | // that can be stopped by cancelling its root context. 30 | type Controller struct { 31 | // a Controller representing the virtual workspace for the APIExport 32 | obj controller.Controller 33 | 34 | // a signal that is closed when the vwController has stopped 35 | stopped chan struct{} 36 | 37 | // a function that is used to stop the vwController 38 | cancelFunc context.CancelCauseFunc 39 | } 40 | 41 | func NewController(upstream controller.Controller) (Controller, error) { 42 | return Controller{ 43 | obj: upstream, 44 | }, nil 45 | } 46 | 47 | // Start starts the wrapped controller. 48 | func (c *Controller) Start(ctx context.Context, log *zap.SugaredLogger) error { 49 | if c.obj == nil { 50 | return errors.New("cannot restart a stopped controller") 51 | } 52 | 53 | if c.stopped != nil { 54 | return errors.New("controller is already running") 55 | } 56 | 57 | ctrlCtx, cancel := context.WithCancelCause(ctx) 58 | 59 | c.cancelFunc = cancel 60 | c.stopped = make(chan struct{}) 61 | 62 | // start the controller in a new goroutine 63 | go func() { 64 | defer close(c.stopped) 65 | 66 | // this call blocks until ctrlCtx is done or an error occurs 67 | // like failing to start the watches 68 | if err := c.obj.Start(ctrlCtx); err != nil { 69 | log.Errorw("Controller has failed", zap.Error(err)) 70 | } 71 | 72 | cancel(errors.New("closing to prevent leakage")) 73 | 74 | c.obj = nil 75 | c.cancelFunc = nil 76 | }() 77 | 78 | return nil 79 | } 80 | 81 | func (c *Controller) Running() bool { 82 | if c.obj == nil { 83 | return false 84 | } 85 | 86 | if c.stopped == nil { 87 | return false 88 | } 89 | 90 | select { 91 | case <-c.stopped: 92 | return false 93 | 94 | default: 95 | return true 96 | } 97 | } 98 | 99 | func (c *Controller) Stop(log *zap.SugaredLogger, cause error) error { 100 | if !c.Running() { 101 | return errors.New("controller is not running") 102 | } 103 | 104 | c.cancelFunc(cause) 105 | log.Info("Waiting for controller to shut down…") 106 | <-c.stopped 107 | log.Info("Controller has finished shutting down.") 108 | 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /internal/controllerutil/handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package controllerutil 18 | 19 | import ( 20 | "context" 21 | 22 | "k8s.io/apimachinery/pkg/types" 23 | ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client" 24 | "sigs.k8s.io/controller-runtime/pkg/handler" 25 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 26 | ) 27 | 28 | // EnqueueConst returns a handler that returns a reconcile request that will contain 29 | // the given value as the request's name. 30 | func EnqueueConst[O ctrlruntimeclient.Object](value string) handler.TypedEventHandler[O, reconcile.Request] { 31 | return handler.TypedEnqueueRequestsFromMapFunc(func(_ context.Context, _ O) []reconcile.Request { 32 | return []reconcile.Request{{ 33 | NamespacedName: types.NamespacedName{ 34 | Name: value, 35 | Namespace: "", 36 | }, 37 | }} 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /internal/controllerutil/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package predicate 18 | 19 | import ( 20 | "k8s.io/apimachinery/pkg/labels" 21 | ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client" 22 | "sigs.k8s.io/controller-runtime/pkg/event" 23 | "sigs.k8s.io/controller-runtime/pkg/predicate" 24 | ) 25 | 26 | // Factory returns a predicate func that applies the given filter function 27 | // on CREATE, UPDATE and DELETE events. For UPDATE events, the filter is applied 28 | // to both the old and new object and OR's the result. 29 | func Factory(filter func(o ctrlruntimeclient.Object) bool) predicate.Funcs { 30 | if filter == nil { 31 | return predicate.Funcs{} 32 | } 33 | 34 | return predicate.Funcs{ 35 | CreateFunc: func(e event.CreateEvent) bool { 36 | return filter(e.Object) 37 | }, 38 | UpdateFunc: func(e event.UpdateEvent) bool { 39 | return filter(e.ObjectOld) || filter(e.ObjectNew) 40 | }, 41 | DeleteFunc: func(e event.DeleteEvent) bool { 42 | return filter(e.Object) 43 | }, 44 | } 45 | } 46 | 47 | func ByLabels(selector labels.Selector) predicate.Funcs { 48 | return Factory(func(o ctrlruntimeclient.Object) bool { 49 | return selector.Matches(labels.Set(o.GetLabels())) 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /internal/crypto/hash.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package crypto 18 | 19 | import ( 20 | "crypto/sha1" 21 | "encoding/hex" 22 | "encoding/json" 23 | "fmt" 24 | ) 25 | 26 | func Hash(data any) string { 27 | hash := sha1.New() 28 | 29 | var err error 30 | switch asserted := data.(type) { 31 | case string: 32 | _, err = hash.Write([]byte(asserted)) 33 | case []byte: 34 | _, err = hash.Write(asserted) 35 | default: 36 | err = json.NewEncoder(hash).Encode(data) 37 | } 38 | 39 | if err != nil { 40 | // This is not something that should ever happen at runtime and is also not 41 | // something we can really gracefully handle, so crashing and restarting might 42 | // be a good way to signal the service owner that something is up. 43 | panic(fmt.Sprintf("Failed to hash: %v", err)) 44 | } 45 | 46 | return hex.EncodeToString(hash.Sum(nil)) 47 | } 48 | 49 | func ShortHash(data any) string { 50 | return Hash(data)[:20] 51 | } 52 | -------------------------------------------------------------------------------- /internal/kcp/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kcp 18 | 19 | const ( 20 | // IdentityClusterName is the name of the logicalcluster that is backing the 21 | // current kcp workspace. Within each kcp workspace one can query for this 22 | // logicalcluster to resolve the workspace's path (e.g. "root:org1:teamx") 23 | // the logicalcluster name (e.g. "984235jkhwfowt45"). 24 | IdentityClusterName = "cluster" 25 | ) 26 | -------------------------------------------------------------------------------- /internal/options/set_flag.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package options 18 | 19 | import ( 20 | "sort" 21 | "strings" 22 | 23 | "github.com/spf13/pflag" 24 | 25 | "k8s.io/apimachinery/pkg/util/sets" 26 | ) 27 | 28 | // SetFlag wraps a given set so it can be used as a CLI flag. 29 | func SetFlag(set *sets.Set[string]) pflag.Value { 30 | return &setFlag{set: set} 31 | } 32 | 33 | type setFlag struct { 34 | set *sets.Set[string] 35 | } 36 | 37 | func (f *setFlag) String() string { 38 | return strings.Join(sort.StringSlice(f.set.UnsortedList()), ",") 39 | } 40 | 41 | func (f *setFlag) Set(value string) error { 42 | // clear set content 43 | f.set.Delete(f.set.UnsortedList()...) 44 | 45 | if value != "" { 46 | for _, val := range strings.Split(value, ",") { 47 | val = strings.TrimSpace(val) 48 | if val != "" { 49 | f.set.Insert(val) 50 | } 51 | } 52 | } 53 | 54 | return nil 55 | } 56 | 57 | func (f *setFlag) Type() string { 58 | return "stringset" 59 | } 60 | -------------------------------------------------------------------------------- /internal/sync/apis/dummy/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // +groupName=dummy.example.com 18 | // +versionName=v1alpha1 19 | // +kubebuilder:object:generate=true 20 | package v1alpha1 21 | -------------------------------------------------------------------------------- /internal/sync/apis/dummy/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | "fmt" 21 | 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/runtime/schema" 25 | "k8s.io/client-go/kubernetes/scheme" 26 | ) 27 | 28 | func init() { 29 | if err := AddToScheme(scheme.Scheme); err != nil { 30 | panic(fmt.Sprintf("failed to add dummy scheme: %v", err)) 31 | } 32 | } 33 | 34 | // GroupName is the group name use in this package. 35 | const GroupName = "dummy.example.com" 36 | const GroupVersion = "v1alpha1" 37 | 38 | var ( 39 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 40 | AddToScheme = SchemeBuilder.AddToScheme 41 | 42 | // SchemeGroupVersion is group version used to register these objects. 43 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} 44 | ) 45 | 46 | // Resource takes an unqualified resource and returns a Group qualified GroupResource. 47 | func Resource(resource string) schema.GroupResource { 48 | return SchemeGroupVersion.WithResource(resource).GroupResource() 49 | } 50 | 51 | // Adds the list of known types to api.Scheme. 52 | func addKnownTypes(scheme *runtime.Scheme) error { 53 | scheme.AddKnownTypes(SchemeGroupVersion, 54 | &NamespacedThing{}, 55 | &NamespacedThingList{}, 56 | &Thing{}, 57 | &ThingList{}, 58 | &ThingWithStatus{}, 59 | &ThingWithStatusList{}, 60 | &ThingWithStatusSubresource{}, 61 | &ThingWithStatusSubresourceList{}, 62 | ) 63 | 64 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /internal/sync/apis/dummy/v1alpha1/thing.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // +genclient 24 | // +kubebuilder:object:root=true 25 | // +kubebuilder:resource:scope=Cluster 26 | // +kubebuilder:subresource:status 27 | 28 | type Thing struct { 29 | metav1.TypeMeta `json:",inline"` 30 | metav1.ObjectMeta `json:"metadata,omitempty"` 31 | 32 | Spec ThingSpec `json:"spec"` 33 | } 34 | 35 | type ThingSpec struct { 36 | Username string `json:"username"` 37 | Kink string `json:"kink"` 38 | Address string `json:"address,omitempty"` 39 | } 40 | 41 | // +kubebuilder:object:root=true 42 | 43 | // ThingList contains a list of Things. 44 | type ThingList struct { 45 | metav1.TypeMeta `json:",inline"` 46 | metav1.ListMeta `json:"metadata,omitempty"` 47 | Items []Thing `json:"items"` 48 | } 49 | -------------------------------------------------------------------------------- /internal/sync/apis/dummy/v1alpha1/thing_namespaced.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // +genclient 24 | // +kubebuilder:object:root=true 25 | // +kubebuilder:subresource:status 26 | 27 | type NamespacedThing struct { 28 | metav1.TypeMeta `json:",inline"` 29 | metav1.ObjectMeta `json:"metadata,omitempty"` 30 | 31 | Spec ThingSpec `json:"spec"` 32 | } 33 | 34 | // +kubebuilder:object:root=true 35 | 36 | // NamespacedThingList contains a list of NamespacedThings. 37 | type NamespacedThingList struct { 38 | metav1.TypeMeta `json:",inline"` 39 | metav1.ListMeta `json:"metadata,omitempty"` 40 | Items []NamespacedThing `json:"items"` 41 | } 42 | -------------------------------------------------------------------------------- /internal/sync/apis/dummy/v1alpha1/thing_real_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // +genclient 24 | // +kubebuilder:object:root=true 25 | // +kubebuilder:resource:scope=Cluster 26 | // +kubebuilder:subresource:status 27 | 28 | type ThingWithStatusSubresource struct { 29 | metav1.TypeMeta `json:",inline"` 30 | metav1.ObjectMeta `json:"metadata,omitempty"` 31 | 32 | Spec ThingSpec `json:"spec"` 33 | Status ThingStatus `json:"status,omitempty"` 34 | } 35 | 36 | // +kubebuilder:object:root=true 37 | 38 | // ThingWithStatusSubresourceList contains a list of ThingWithStatusSubresources. 39 | type ThingWithStatusSubresourceList struct { 40 | metav1.TypeMeta `json:",inline"` 41 | metav1.ListMeta `json:"metadata,omitempty"` 42 | Items []ThingWithStatusSubresource `json:"items"` 43 | } 44 | -------------------------------------------------------------------------------- /internal/sync/apis/dummy/v1alpha1/thing_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // +genclient 24 | // +kubebuilder:object:root=true 25 | // +kubebuilder:resource:scope=Cluster 26 | 27 | type ThingWithStatus struct { 28 | metav1.TypeMeta `json:",inline"` 29 | metav1.ObjectMeta `json:"metadata,omitempty"` 30 | 31 | Spec ThingSpec `json:"spec"` 32 | 33 | // NB: In this test resource, status exists but is *NOT* a subresource! 34 | Status ThingStatus `json:"status,omitempty"` 35 | } 36 | 37 | type ThingStatus struct { 38 | CurrentVersion string `json:"currentVersion"` 39 | } 40 | 41 | // +kubebuilder:object:root=true 42 | 43 | // ThingWithStatusList contains a list of ThingWithStatus objects. 44 | type ThingWithStatusList struct { 45 | metav1.TypeMeta `json:",inline"` 46 | metav1.ListMeta `json:"metadata,omitempty"` 47 | Items []ThingWithStatus `json:"items"` 48 | } 49 | -------------------------------------------------------------------------------- /internal/sync/context.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package sync 18 | 19 | import ( 20 | "context" 21 | 22 | "github.com/kcp-dev/logicalcluster/v3" 23 | 24 | "sigs.k8s.io/controller-runtime/pkg/kontext" 25 | ) 26 | 27 | type Context struct { 28 | clusterName logicalcluster.Name 29 | workspacePath logicalcluster.Path 30 | local context.Context 31 | remote context.Context 32 | } 33 | 34 | func NewContext(local, remote context.Context) Context { 35 | clusterName, ok := kontext.ClusterFrom(remote) 36 | if !ok { 37 | panic("Provided remote context does not contain cluster name.") 38 | } 39 | 40 | return Context{ 41 | clusterName: clusterName, 42 | local: local, 43 | remote: remote, 44 | } 45 | } 46 | 47 | func (c *Context) WithWorkspacePath(path logicalcluster.Path) Context { 48 | return Context{ 49 | clusterName: c.clusterName, 50 | workspacePath: path, 51 | local: c.local, 52 | remote: c.remote, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /internal/sync/context_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package sync 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/kcp-dev/logicalcluster/v3" 23 | 24 | "sigs.k8s.io/controller-runtime/pkg/kontext" 25 | ) 26 | 27 | func TestNewContext(t *testing.T) { 28 | clusterName := logicalcluster.Name("foo") 29 | ctx := kontext.WithCluster(t.Context(), clusterName) 30 | 31 | combinedCtx := NewContext(t.Context(), ctx) 32 | 33 | if combinedCtx.clusterName != clusterName { 34 | t.Fatalf("Expected function to recognize the cluster name in the context, but got %q", combinedCtx.clusterName) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /internal/sync/crd/dummy.example.com_namespacedthings.yaml: -------------------------------------------------------------------------------- 1 | # This file has been generated by hack/update-codegen-crds.sh, DO NOT EDIT. 2 | 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.16.5 8 | name: namespacedthings.dummy.example.com 9 | spec: 10 | group: dummy.example.com 11 | names: 12 | kind: NamespacedThing 13 | listKind: NamespacedThingList 14 | plural: namespacedthings 15 | singular: namespacedthing 16 | scope: Namespaced 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | properties: 22 | apiVersion: 23 | description: |- 24 | APIVersion defines the versioned schema of this representation of an object. 25 | Servers should convert recognized schemas to the latest internal value, and 26 | may reject unrecognized values. 27 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 28 | type: string 29 | kind: 30 | description: |- 31 | Kind is a string value representing the REST resource this object represents. 32 | Servers may infer this from the endpoint the client submits requests to. 33 | Cannot be updated. 34 | In CamelCase. 35 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 36 | type: string 37 | metadata: 38 | type: object 39 | spec: 40 | properties: 41 | address: 42 | type: string 43 | kink: 44 | type: string 45 | username: 46 | type: string 47 | required: 48 | - kink 49 | - username 50 | type: object 51 | required: 52 | - spec 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | -------------------------------------------------------------------------------- /internal/sync/crd/dummy.example.com_things.yaml: -------------------------------------------------------------------------------- 1 | # This file has been generated by hack/update-codegen-crds.sh, DO NOT EDIT. 2 | 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.16.5 8 | name: things.dummy.example.com 9 | spec: 10 | group: dummy.example.com 11 | names: 12 | kind: Thing 13 | listKind: ThingList 14 | plural: things 15 | singular: thing 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | properties: 22 | apiVersion: 23 | description: |- 24 | APIVersion defines the versioned schema of this representation of an object. 25 | Servers should convert recognized schemas to the latest internal value, and 26 | may reject unrecognized values. 27 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 28 | type: string 29 | kind: 30 | description: |- 31 | Kind is a string value representing the REST resource this object represents. 32 | Servers may infer this from the endpoint the client submits requests to. 33 | Cannot be updated. 34 | In CamelCase. 35 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 36 | type: string 37 | metadata: 38 | type: object 39 | spec: 40 | properties: 41 | address: 42 | type: string 43 | kink: 44 | type: string 45 | username: 46 | type: string 47 | required: 48 | - kink 49 | - username 50 | type: object 51 | required: 52 | - spec 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | -------------------------------------------------------------------------------- /internal/sync/crd/dummy.example.com_thingwithstatuses.yaml: -------------------------------------------------------------------------------- 1 | # This file has been generated by hack/update-codegen-crds.sh, DO NOT EDIT. 2 | 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.16.5 8 | name: thingwithstatuses.dummy.example.com 9 | spec: 10 | group: dummy.example.com 11 | names: 12 | kind: ThingWithStatus 13 | listKind: ThingWithStatusList 14 | plural: thingwithstatuses 15 | singular: thingwithstatus 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | properties: 22 | apiVersion: 23 | description: |- 24 | APIVersion defines the versioned schema of this representation of an object. 25 | Servers should convert recognized schemas to the latest internal value, and 26 | may reject unrecognized values. 27 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 28 | type: string 29 | kind: 30 | description: |- 31 | Kind is a string value representing the REST resource this object represents. 32 | Servers may infer this from the endpoint the client submits requests to. 33 | Cannot be updated. 34 | In CamelCase. 35 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 36 | type: string 37 | metadata: 38 | type: object 39 | spec: 40 | properties: 41 | address: 42 | type: string 43 | kink: 44 | type: string 45 | username: 46 | type: string 47 | required: 48 | - kink 49 | - username 50 | type: object 51 | status: 52 | description: 'NB: In this test resource, status exists but is *NOT* a subresource!' 53 | properties: 54 | currentVersion: 55 | type: string 56 | required: 57 | - currentVersion 58 | type: object 59 | required: 60 | - spec 61 | type: object 62 | served: true 63 | storage: true 64 | -------------------------------------------------------------------------------- /internal/sync/crd/dummy.example.com_thingwithstatussubresources.yaml: -------------------------------------------------------------------------------- 1 | # This file has been generated by hack/update-codegen-crds.sh, DO NOT EDIT. 2 | 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.16.5 8 | name: thingwithstatussubresources.dummy.example.com 9 | spec: 10 | group: dummy.example.com 11 | names: 12 | kind: ThingWithStatusSubresource 13 | listKind: ThingWithStatusSubresourceList 14 | plural: thingwithstatussubresources 15 | singular: thingwithstatussubresource 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | properties: 22 | apiVersion: 23 | description: |- 24 | APIVersion defines the versioned schema of this representation of an object. 25 | Servers should convert recognized schemas to the latest internal value, and 26 | may reject unrecognized values. 27 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 28 | type: string 29 | kind: 30 | description: |- 31 | Kind is a string value representing the REST resource this object represents. 32 | Servers may infer this from the endpoint the client submits requests to. 33 | Cannot be updated. 34 | In CamelCase. 35 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 36 | type: string 37 | metadata: 38 | type: object 39 | spec: 40 | properties: 41 | address: 42 | type: string 43 | kink: 44 | type: string 45 | username: 46 | type: string 47 | required: 48 | - kink 49 | - username 50 | type: object 51 | status: 52 | properties: 53 | currentVersion: 54 | type: string 55 | required: 56 | - currentVersion 57 | type: object 58 | required: 59 | - spec 60 | type: object 61 | served: true 62 | storage: true 63 | subresources: 64 | status: {} 65 | -------------------------------------------------------------------------------- /internal/sync/init_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package sync 18 | 19 | import ( 20 | "time" 21 | 22 | dummyv1alpha1 "github.com/kcp-dev/api-syncagent/internal/sync/apis/dummy/v1alpha1" 23 | 24 | corev1 "k8s.io/api/core/v1" 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/apimachinery/pkg/runtime" 27 | ) 28 | 29 | var testScheme *runtime.Scheme 30 | 31 | func init() { 32 | testScheme = runtime.NewScheme() 33 | if err := dummyv1alpha1.AddToScheme(testScheme); err != nil { 34 | panic(err) 35 | } 36 | if err := corev1.AddToScheme(testScheme); err != nil { 37 | panic(err) 38 | } 39 | } 40 | 41 | var nonEmptyTime = metav1.Time{ 42 | Time: time.Now(), 43 | } 44 | -------------------------------------------------------------------------------- /internal/sync/meta_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package sync 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/kcp-dev/logicalcluster/v3" 23 | 24 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 | ) 27 | 28 | func createNewObject(name, namespace string) metav1.Object { 29 | obj := &unstructured.Unstructured{} 30 | obj.SetName(name) 31 | obj.SetNamespace(namespace) 32 | 33 | return obj 34 | } 35 | 36 | func TestObjectKey(t *testing.T) { 37 | testcases := []struct { 38 | object metav1.Object 39 | clusterName logicalcluster.Name 40 | workspacePath logicalcluster.Path 41 | expected string 42 | }{ 43 | { 44 | object: createNewObject("test", ""), 45 | clusterName: "", 46 | expected: "test", 47 | }, 48 | { 49 | object: createNewObject("test", "namespace"), 50 | clusterName: "", 51 | expected: "namespace/test", 52 | }, 53 | { 54 | object: createNewObject("test", ""), 55 | clusterName: "abc123", 56 | expected: "abc123|test", 57 | }, 58 | { 59 | object: createNewObject("test", "namespace"), 60 | clusterName: "abc123", 61 | expected: "abc123|namespace/test", 62 | }, 63 | { 64 | object: createNewObject("test", "namespace"), 65 | clusterName: "abc123", 66 | workspacePath: logicalcluster.NewPath("this:should:not:appear:in:the:key"), 67 | expected: "abc123|namespace/test", 68 | }, 69 | } 70 | 71 | for _, testcase := range testcases { 72 | t.Run("", func(t *testing.T) { 73 | key := newObjectKey(testcase.object, testcase.clusterName, testcase.workspacePath) 74 | 75 | if stringified := key.String(); stringified != testcase.expected { 76 | t.Fatalf("Expected %q but got %q.", testcase.expected, stringified) 77 | } 78 | }) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /internal/sync/templating/templating.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package templating 18 | 19 | import ( 20 | "bytes" 21 | "encoding/hex" 22 | "fmt" 23 | "strings" 24 | "text/template" 25 | 26 | "crypto/sha3" 27 | "github.com/Masterminds/sprig/v3" 28 | 29 | "github.com/kcp-dev/api-syncagent/internal/crypto" 30 | ) 31 | 32 | func Render(tpl string, data any) (string, error) { 33 | parsed, err := template.New("inline").Funcs(templateFuncMap()).Parse(tpl) 34 | if err != nil { 35 | return "", fmt.Errorf("failed to parse: %w", err) 36 | } 37 | 38 | var buf bytes.Buffer 39 | if err := parsed.Execute(&buf, data); err != nil { 40 | return "", fmt.Errorf("failed to evaluate: %w", err) 41 | } 42 | 43 | return strings.TrimSpace(buf.String()), nil 44 | } 45 | 46 | func templateFuncMap() template.FuncMap { 47 | funcs := sprig.TxtFuncMap() 48 | funcs["sha3sum"] = sha3sum 49 | funcs["sha3short"] = sha3short 50 | 51 | // shortHash is included for backwards compatibility with the old naming rules, 52 | // new installations should not use it because it relies on SHA-1. Instead use 53 | // sha3short. 54 | funcs["shortHash"] = crypto.ShortHash 55 | 56 | return funcs 57 | } 58 | 59 | func sha3sum(input string) string { 60 | hash := sha3.Sum256([]byte(input)) 61 | return hex.EncodeToString(hash[:]) 62 | } 63 | 64 | // sha3short supports exactly 1 optional length argument. If not given, length defaults to 20. 65 | func sha3short(input string, lengths ...int) (string, error) { 66 | var length int 67 | switch len(lengths) { 68 | case 0: 69 | length = 20 70 | case 1: 71 | length = lengths[0] 72 | default: 73 | return "", fmt.Errorf("sha3short: expected at most one length argument, got %d", len(lengths)) 74 | } 75 | 76 | if length <= 0 { 77 | return "", fmt.Errorf("sha3short: invalid length %d", length) 78 | } 79 | 80 | hash := sha3sum(input) 81 | 82 | if length > len(hash) { 83 | length = len(hash) 84 | } 85 | 86 | return hash[:length], nil 87 | } 88 | -------------------------------------------------------------------------------- /internal/sync/templating/templating_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package templating 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/kcp-dev/logicalcluster/v3" 23 | 24 | "github.com/kcp-dev/api-syncagent/test/crds" 25 | "github.com/kcp-dev/api-syncagent/test/utils" 26 | 27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 | ) 29 | 30 | func TestRender(t *testing.T) { 31 | clusterName := logicalcluster.Name("12386rtr4u") 32 | clusterPath := logicalcluster.NewPath("root:yadda:yadda") 33 | 34 | crontab := &crds.Crontab{ 35 | ObjectMeta: metav1.ObjectMeta{ 36 | Name: "my-crontab", 37 | Namespace: "default", 38 | }, 39 | Spec: crds.CrontabSpec{ 40 | Image: "ubuntu:latest", 41 | }, 42 | } 43 | 44 | object := utils.ToUnstructured(t, crontab) 45 | object.SetAPIVersion("kcp.example.com/v1") 46 | object.SetKind("CronTab") 47 | 48 | testcases := []struct { 49 | name string 50 | template string 51 | data any 52 | expected string 53 | }{ 54 | { 55 | name: "simple object access", 56 | data: newLocalObjectNamingContext(object, clusterName, clusterPath), 57 | template: `{{ .Object.spec.image }}`, 58 | expected: crontab.Spec.Image, 59 | }, 60 | { 61 | name: "default empty fields", 62 | data: newLocalObjectNamingContext(object, clusterName, clusterPath), 63 | template: `{{ .Object.spec.spec | default "test" }}`, 64 | expected: "test", 65 | }, 66 | { 67 | name: "default non-existing field", 68 | data: newLocalObjectNamingContext(object, clusterName, clusterPath), 69 | template: `{{ .Object.does.not.exist | default "test" }}`, 70 | expected: "test", 71 | }, 72 | } 73 | 74 | for _, testcase := range testcases { 75 | t.Run(testcase.name, func(t *testing.T) { 76 | rendered, err := Render(testcase.template, testcase.data) 77 | if err != nil { 78 | t.Fatalf("Unexpected error: %v.", err) 79 | } 80 | 81 | if rendered != testcase.expected { 82 | t.Errorf("Expected %q, but got %q.", testcase.expected, rendered) 83 | } 84 | }) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /internal/sync/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package sync 18 | 19 | import ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client" 20 | 21 | const ( 22 | // deletionFinalizer is the finalizer put on remote objects to prevent 23 | // them from being deleted before the local objects can be cleaned up. 24 | deletionFinalizer = "syncagent.kcp.io/cleanup" 25 | 26 | // The following 4 labels/annotations are put on local objects to link them to their 27 | // origin remote objects. Note that the cluster *path* label is optional and 28 | // has to be enabled per PublishedResource. 29 | 30 | remoteObjectClusterLabel = "syncagent.kcp.io/remote-object-cluster" 31 | remoteObjectNamespaceHashLabel = "syncagent.kcp.io/remote-object-namespace-hash" 32 | remoteObjectNameHashLabel = "syncagent.kcp.io/remote-object-name-hash" 33 | 34 | remoteObjectNamespaceAnnotation = "syncagent.kcp.io/remote-object-namespace" 35 | remoteObjectNameAnnotation = "syncagent.kcp.io/remote-object-name" 36 | 37 | remoteObjectWorkspacePathAnnotation = "syncagent.kcp.io/remote-object-workspace-path" 38 | 39 | // agentNameLabel contains the Sync Agent's name and is used to allow multiple Sync Agents 40 | // on the same service cluster, syncing *the same* API to different kcp's. 41 | agentNameLabel = "syncagent.kcp.io/agent-name" 42 | 43 | // objectStateLabelName is put on object state Secrets to allow for easier mass deletions 44 | // if ever necessary. 45 | objectStateLabelName = "syncagent.kcp.io/object-state" 46 | 47 | // objectStateLabelValue is the value of the objectStateLabelName label. 48 | objectStateLabelValue = "true" 49 | 50 | // relatedObjectAnnotationPrefix is the prefix for the annotation that is placed on 51 | // objects in the kcp workspaces, informing the user about the existence of a related 52 | // object. The identifier of the related object is appended to this to form the 53 | // full annotation name, the annotation value is a JSON string containing GVK and 54 | // metadata of the related object. 55 | relatedObjectAnnotationPrefix = "related-resources.syncagent.kcp.io/" 56 | ) 57 | 58 | func OwnedBy(obj ctrlruntimeclient.Object, agentName string) bool { 59 | return obj.GetLabels()[agentNameLabel] == agentName 60 | } 61 | -------------------------------------------------------------------------------- /internal/test/diff/diff.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package diff 18 | 19 | import ( 20 | "fmt" 21 | "reflect" 22 | "strings" 23 | 24 | "github.com/pmezard/go-difflib/difflib" 25 | 26 | apiequality "k8s.io/apimachinery/pkg/api/equality" 27 | "k8s.io/apimachinery/pkg/util/sets" 28 | "sigs.k8s.io/yaml" 29 | ) 30 | 31 | func DeepEqual(expected, actual interface{}) bool { 32 | return reflect.DeepEqual(expected, actual) 33 | } 34 | 35 | func SemanticallyEqual(expected, actual interface{}) bool { 36 | return apiequality.Semantic.DeepEqual(expected, actual) 37 | } 38 | 39 | // these types are copied directly from apimachinery/pkg/util/sets 40 | 41 | type ordered interface { 42 | integer | float | ~string 43 | } 44 | 45 | type integer interface { 46 | signed | unsigned 47 | } 48 | 49 | type float interface { 50 | ~float32 | ~float64 51 | } 52 | 53 | type signed interface { 54 | ~int | ~int8 | ~int16 | ~int32 | ~int64 55 | } 56 | 57 | type unsigned interface { 58 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr 59 | } 60 | 61 | func SetDiff[T ordered](expected, actual sets.Set[T]) string { 62 | return ObjectDiff(sets.List(expected), sets.List(actual)) 63 | } 64 | 65 | func ObjectDiff(expected, actual interface{}) string { 66 | expectedYAML, err := yaml.Marshal(expected) 67 | if err != nil { 68 | return fmt.Sprintf("", err) 69 | } 70 | 71 | actualYAML, err := yaml.Marshal(actual) 72 | if err != nil { 73 | return fmt.Sprintf("", err) 74 | } 75 | 76 | return StringDiff(string(expectedYAML), string(actualYAML)) 77 | } 78 | 79 | func StringDiff(expected, actual string) string { 80 | expected = strings.TrimSpace(expected) 81 | actual = strings.TrimSpace(actual) 82 | 83 | diff := difflib.UnifiedDiff{ 84 | A: difflib.SplitLines(expected), 85 | B: difflib.SplitLines(actual), 86 | FromFile: "Expected", 87 | ToFile: "Actual", 88 | Context: 3, 89 | } 90 | 91 | unidifiedDiff, err := difflib.GetUnifiedDiffString(diff) 92 | if err != nil { 93 | return fmt.Sprintf("", err) 94 | } 95 | 96 | return unidifiedDiff 97 | } 98 | -------------------------------------------------------------------------------- /internal/version/app.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package version 18 | 19 | // These variables get fed by ldflags during compilation. 20 | var ( 21 | // gitVersion is a variable containing the git commit identifier 22 | // (usually the output of `git describe`, i.e. not necessarily a 23 | // static tag name); for a tagged Sync Agent release, this value is identical 24 | // to kubermaticDockerTag, for untagged builds this is the `git describe` 25 | // output. 26 | // Importantly, this value will only ever go up, even for untagged builds, 27 | // but is not monotone (gaps can occur, this can go from v2.20.0-1234-d6aef3 28 | // to v2.34.0-912-dd79178e to v3.0.1). 29 | // Also this value does not necessarily reflect the current release branch, 30 | // as releases are tagged on the release branch and on those tags are not 31 | // visible from the main branch. 32 | gitVersion string 33 | // gitHead is the full SHA hash of the Git commit the application was built for. 34 | gitHead string 35 | ) 36 | 37 | type AppVersion struct { 38 | GitVersion string 39 | GitHead string 40 | } 41 | 42 | func NewAppVersion() AppVersion { 43 | return AppVersion{ 44 | GitVersion: gitVersion, 45 | GitHead: gitHead, 46 | } 47 | } 48 | 49 | func NewFakeAppVersion() AppVersion { 50 | return AppVersion{ 51 | GitVersion: "v0.0.0-42-test", 52 | GitHead: "d9c09114135c62e207b30891899e7e1ad2493f38", 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sdk/apis/syncagent/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // +groupName=syncagent.kcp.io 18 | // +versionName=v1alpha1 19 | // +kubebuilder:object:generate=true 20 | package v1alpha1 21 | -------------------------------------------------------------------------------- /sdk/apis/syncagent/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | "fmt" 21 | 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/runtime/schema" 25 | "k8s.io/client-go/kubernetes/scheme" 26 | ) 27 | 28 | func init() { 29 | if err := AddToScheme(scheme.Scheme); err != nil { 30 | panic(fmt.Sprintf("failed to add syncagent.kcp.io scheme: %v", err)) 31 | } 32 | } 33 | 34 | // GroupName is the group name use in this package. 35 | const GroupName = "syncagent.kcp.io" 36 | const GroupVersion = "v1alpha1" 37 | 38 | var ( 39 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 40 | AddToScheme = SchemeBuilder.AddToScheme 41 | 42 | // SchemeGroupVersion is group version used to register these objects. 43 | SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} 44 | ) 45 | 46 | // Resource takes an unqualified resource and returns a Group qualified GroupResource. 47 | func Resource(resource string) schema.GroupResource { 48 | return SchemeGroupVersion.WithResource(resource).GroupResource() 49 | } 50 | 51 | // Adds the list of known types to api.Scheme. 52 | func addKnownTypes(scheme *runtime.Scheme) error { 53 | scheme.AddKnownTypes(SchemeGroupVersion, 54 | &PublishedResource{}, 55 | &PublishedResourceList{}, 56 | ) 57 | 58 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /sdk/apis/syncagent/v1alpha1/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | const ( 20 | // AgentNameAnnotation records which Sync Agent has created an APIResourceSchema. 21 | AgentNameAnnotation = "syncagent.kcp.io/agent-name" 22 | 23 | // AgentNameLabel records which Sync Agent has created an APIResourceSchema. 24 | AgentNameLabel = "syncagent.kcp.io/agent-name" 25 | 26 | // SourceGenerationAnnotation is the annotation on APIResourceSchemas that tells us 27 | // what generation of the CRD it was based on. This can be helpful in debugging, 28 | // as ARS resources cannot be updated, i.e. changes to CRDs are not reflected in ARS. 29 | SourceGenerationAnnotation = "syncagent.kcp.io/source-generation" 30 | ) 31 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/internal/internal.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package internal 20 | 21 | import ( 22 | "fmt" 23 | "sync" 24 | 25 | typed "sigs.k8s.io/structured-merge-diff/v4/typed" 26 | ) 27 | 28 | func Parser() *typed.Parser { 29 | parserOnce.Do(func() { 30 | var err error 31 | parser, err = typed.NewParser(schemaYAML) 32 | if err != nil { 33 | panic(fmt.Sprintf("Failed to parse schema: %v", err)) 34 | } 35 | }) 36 | return parser 37 | } 38 | 39 | var parserOnce sync.Once 40 | var parser *typed.Parser 41 | var schemaYAML = typed.YAMLObject(`types: 42 | - name: __untyped_atomic_ 43 | scalar: untyped 44 | list: 45 | elementType: 46 | namedType: __untyped_atomic_ 47 | elementRelationship: atomic 48 | map: 49 | elementType: 50 | namedType: __untyped_atomic_ 51 | elementRelationship: atomic 52 | - name: __untyped_deduced_ 53 | scalar: untyped 54 | list: 55 | elementType: 56 | namedType: __untyped_atomic_ 57 | elementRelationship: atomic 58 | map: 59 | elementType: 60 | namedType: __untyped_deduced_ 61 | elementRelationship: separable 62 | `) 63 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/publishedresourcestatus.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // PublishedResourceStatusApplyConfiguration represents a declarative configuration of the PublishedResourceStatus type for use 22 | // with apply. 23 | type PublishedResourceStatusApplyConfiguration struct { 24 | ResourceSchemaName *string `json:"resourceSchemaName,omitempty"` 25 | } 26 | 27 | // PublishedResourceStatusApplyConfiguration constructs a declarative configuration of the PublishedResourceStatus type for use with 28 | // apply. 29 | func PublishedResourceStatus() *PublishedResourceStatusApplyConfiguration { 30 | return &PublishedResourceStatusApplyConfiguration{} 31 | } 32 | 33 | // WithResourceSchemaName sets the ResourceSchemaName field in the declarative configuration to the given value 34 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 35 | // If called multiple times, the ResourceSchemaName field is set to the value of the last call. 36 | func (b *PublishedResourceStatusApplyConfiguration) WithResourceSchemaName(value string) *PublishedResourceStatusApplyConfiguration { 37 | b.ResourceSchemaName = &value 38 | return b 39 | } 40 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/regularexpression.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // RegularExpressionApplyConfiguration represents a declarative configuration of the RegularExpression type for use 22 | // with apply. 23 | type RegularExpressionApplyConfiguration struct { 24 | Pattern *string `json:"pattern,omitempty"` 25 | Replacement *string `json:"replacement,omitempty"` 26 | } 27 | 28 | // RegularExpressionApplyConfiguration constructs a declarative configuration of the RegularExpression type for use with 29 | // apply. 30 | func RegularExpression() *RegularExpressionApplyConfiguration { 31 | return &RegularExpressionApplyConfiguration{} 32 | } 33 | 34 | // WithPattern sets the Pattern field in the declarative configuration to the given value 35 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 36 | // If called multiple times, the Pattern field is set to the value of the last call. 37 | func (b *RegularExpressionApplyConfiguration) WithPattern(value string) *RegularExpressionApplyConfiguration { 38 | b.Pattern = &value 39 | return b 40 | } 41 | 42 | // WithReplacement sets the Replacement field in the declarative configuration to the given value 43 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 44 | // If called multiple times, the Replacement field is set to the value of the last call. 45 | func (b *RegularExpressionApplyConfiguration) WithReplacement(value string) *RegularExpressionApplyConfiguration { 46 | b.Replacement = &value 47 | return b 48 | } 49 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/relatedresourceobject.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // RelatedResourceObjectApplyConfiguration represents a declarative configuration of the RelatedResourceObject type for use 22 | // with apply. 23 | type RelatedResourceObjectApplyConfiguration struct { 24 | RelatedResourceObjectSpecApplyConfiguration `json:",inline"` 25 | Namespace *RelatedResourceObjectSpecApplyConfiguration `json:"namespace,omitempty"` 26 | } 27 | 28 | // RelatedResourceObjectApplyConfiguration constructs a declarative configuration of the RelatedResourceObject type for use with 29 | // apply. 30 | func RelatedResourceObject() *RelatedResourceObjectApplyConfiguration { 31 | return &RelatedResourceObjectApplyConfiguration{} 32 | } 33 | 34 | // WithSelector sets the Selector field in the declarative configuration to the given value 35 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 36 | // If called multiple times, the Selector field is set to the value of the last call. 37 | func (b *RelatedResourceObjectApplyConfiguration) WithSelector(value *RelatedResourceObjectSelectorApplyConfiguration) *RelatedResourceObjectApplyConfiguration { 38 | b.Selector = value 39 | return b 40 | } 41 | 42 | // WithReference sets the Reference field in the declarative configuration to the given value 43 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 44 | // If called multiple times, the Reference field is set to the value of the last call. 45 | func (b *RelatedResourceObjectApplyConfiguration) WithReference(value *RelatedResourceObjectReferenceApplyConfiguration) *RelatedResourceObjectApplyConfiguration { 46 | b.Reference = value 47 | return b 48 | } 49 | 50 | // WithTemplate sets the Template field in the declarative configuration to the given value 51 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 52 | // If called multiple times, the Template field is set to the value of the last call. 53 | func (b *RelatedResourceObjectApplyConfiguration) WithTemplate(value *TemplateExpressionApplyConfiguration) *RelatedResourceObjectApplyConfiguration { 54 | b.Template = value 55 | return b 56 | } 57 | 58 | // WithNamespace sets the Namespace field in the declarative configuration to the given value 59 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 60 | // If called multiple times, the Namespace field is set to the value of the last call. 61 | func (b *RelatedResourceObjectApplyConfiguration) WithNamespace(value *RelatedResourceObjectSpecApplyConfiguration) *RelatedResourceObjectApplyConfiguration { 62 | b.Namespace = value 63 | return b 64 | } 65 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/relatedresourceobjectreference.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // RelatedResourceObjectReferenceApplyConfiguration represents a declarative configuration of the RelatedResourceObjectReference type for use 22 | // with apply. 23 | type RelatedResourceObjectReferenceApplyConfiguration struct { 24 | Path *string `json:"path,omitempty"` 25 | Regex *RegularExpressionApplyConfiguration `json:"regex,omitempty"` 26 | } 27 | 28 | // RelatedResourceObjectReferenceApplyConfiguration constructs a declarative configuration of the RelatedResourceObjectReference type for use with 29 | // apply. 30 | func RelatedResourceObjectReference() *RelatedResourceObjectReferenceApplyConfiguration { 31 | return &RelatedResourceObjectReferenceApplyConfiguration{} 32 | } 33 | 34 | // WithPath sets the Path field in the declarative configuration to the given value 35 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 36 | // If called multiple times, the Path field is set to the value of the last call. 37 | func (b *RelatedResourceObjectReferenceApplyConfiguration) WithPath(value string) *RelatedResourceObjectReferenceApplyConfiguration { 38 | b.Path = &value 39 | return b 40 | } 41 | 42 | // WithRegex sets the Regex field in the declarative configuration to the given value 43 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 44 | // If called multiple times, the Regex field is set to the value of the last call. 45 | func (b *RelatedResourceObjectReferenceApplyConfiguration) WithRegex(value *RegularExpressionApplyConfiguration) *RelatedResourceObjectReferenceApplyConfiguration { 46 | b.Regex = value 47 | return b 48 | } 49 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/relatedresourceobjectspec.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // RelatedResourceObjectSpecApplyConfiguration represents a declarative configuration of the RelatedResourceObjectSpec type for use 22 | // with apply. 23 | type RelatedResourceObjectSpecApplyConfiguration struct { 24 | Selector *RelatedResourceObjectSelectorApplyConfiguration `json:"selector,omitempty"` 25 | Reference *RelatedResourceObjectReferenceApplyConfiguration `json:"reference,omitempty"` 26 | Template *TemplateExpressionApplyConfiguration `json:"template,omitempty"` 27 | } 28 | 29 | // RelatedResourceObjectSpecApplyConfiguration constructs a declarative configuration of the RelatedResourceObjectSpec type for use with 30 | // apply. 31 | func RelatedResourceObjectSpec() *RelatedResourceObjectSpecApplyConfiguration { 32 | return &RelatedResourceObjectSpecApplyConfiguration{} 33 | } 34 | 35 | // WithSelector sets the Selector field in the declarative configuration to the given value 36 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 37 | // If called multiple times, the Selector field is set to the value of the last call. 38 | func (b *RelatedResourceObjectSpecApplyConfiguration) WithSelector(value *RelatedResourceObjectSelectorApplyConfiguration) *RelatedResourceObjectSpecApplyConfiguration { 39 | b.Selector = value 40 | return b 41 | } 42 | 43 | // WithReference sets the Reference field in the declarative configuration to the given value 44 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 45 | // If called multiple times, the Reference field is set to the value of the last call. 46 | func (b *RelatedResourceObjectSpecApplyConfiguration) WithReference(value *RelatedResourceObjectReferenceApplyConfiguration) *RelatedResourceObjectSpecApplyConfiguration { 47 | b.Reference = value 48 | return b 49 | } 50 | 51 | // WithTemplate sets the Template field in the declarative configuration to the given value 52 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 53 | // If called multiple times, the Template field is set to the value of the last call. 54 | func (b *RelatedResourceObjectSpecApplyConfiguration) WithTemplate(value *TemplateExpressionApplyConfiguration) *RelatedResourceObjectSpecApplyConfiguration { 55 | b.Template = value 56 | return b 57 | } 58 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/relatedresourceselectorrewrite.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // RelatedResourceSelectorRewriteApplyConfiguration represents a declarative configuration of the RelatedResourceSelectorRewrite type for use 22 | // with apply. 23 | type RelatedResourceSelectorRewriteApplyConfiguration struct { 24 | Regex *RegularExpressionApplyConfiguration `json:"regex,omitempty"` 25 | Template *TemplateExpressionApplyConfiguration `json:"template,omitempty"` 26 | } 27 | 28 | // RelatedResourceSelectorRewriteApplyConfiguration constructs a declarative configuration of the RelatedResourceSelectorRewrite type for use with 29 | // apply. 30 | func RelatedResourceSelectorRewrite() *RelatedResourceSelectorRewriteApplyConfiguration { 31 | return &RelatedResourceSelectorRewriteApplyConfiguration{} 32 | } 33 | 34 | // WithRegex sets the Regex field in the declarative configuration to the given value 35 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 36 | // If called multiple times, the Regex field is set to the value of the last call. 37 | func (b *RelatedResourceSelectorRewriteApplyConfiguration) WithRegex(value *RegularExpressionApplyConfiguration) *RelatedResourceSelectorRewriteApplyConfiguration { 38 | b.Regex = value 39 | return b 40 | } 41 | 42 | // WithTemplate sets the Template field in the declarative configuration to the given value 43 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 44 | // If called multiple times, the Template field is set to the value of the last call. 45 | func (b *RelatedResourceSelectorRewriteApplyConfiguration) WithTemplate(value *TemplateExpressionApplyConfiguration) *RelatedResourceSelectorRewriteApplyConfiguration { 46 | b.Template = value 47 | return b 48 | } 49 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourcedeletemutation.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ResourceDeleteMutationApplyConfiguration represents a declarative configuration of the ResourceDeleteMutation type for use 22 | // with apply. 23 | type ResourceDeleteMutationApplyConfiguration struct { 24 | Path *string `json:"path,omitempty"` 25 | } 26 | 27 | // ResourceDeleteMutationApplyConfiguration constructs a declarative configuration of the ResourceDeleteMutation type for use with 28 | // apply. 29 | func ResourceDeleteMutation() *ResourceDeleteMutationApplyConfiguration { 30 | return &ResourceDeleteMutationApplyConfiguration{} 31 | } 32 | 33 | // WithPath sets the Path field in the declarative configuration to the given value 34 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 35 | // If called multiple times, the Path field is set to the value of the last call. 36 | func (b *ResourceDeleteMutationApplyConfiguration) WithPath(value string) *ResourceDeleteMutationApplyConfiguration { 37 | b.Path = &value 38 | return b 39 | } 40 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourcefilter.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | v1 "k8s.io/client-go/applyconfigurations/meta/v1" 23 | ) 24 | 25 | // ResourceFilterApplyConfiguration represents a declarative configuration of the ResourceFilter type for use 26 | // with apply. 27 | type ResourceFilterApplyConfiguration struct { 28 | Namespace *v1.LabelSelectorApplyConfiguration `json:"namespace,omitempty"` 29 | Resource *v1.LabelSelectorApplyConfiguration `json:"resource,omitempty"` 30 | } 31 | 32 | // ResourceFilterApplyConfiguration constructs a declarative configuration of the ResourceFilter type for use with 33 | // apply. 34 | func ResourceFilter() *ResourceFilterApplyConfiguration { 35 | return &ResourceFilterApplyConfiguration{} 36 | } 37 | 38 | // WithNamespace sets the Namespace field in the declarative configuration to the given value 39 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 40 | // If called multiple times, the Namespace field is set to the value of the last call. 41 | func (b *ResourceFilterApplyConfiguration) WithNamespace(value *v1.LabelSelectorApplyConfiguration) *ResourceFilterApplyConfiguration { 42 | b.Namespace = value 43 | return b 44 | } 45 | 46 | // WithResource sets the Resource field in the declarative configuration to the given value 47 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 48 | // If called multiple times, the Resource field is set to the value of the last call. 49 | func (b *ResourceFilterApplyConfiguration) WithResource(value *v1.LabelSelectorApplyConfiguration) *ResourceFilterApplyConfiguration { 50 | b.Resource = value 51 | return b 52 | } 53 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourcemutation.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ResourceMutationApplyConfiguration represents a declarative configuration of the ResourceMutation type for use 22 | // with apply. 23 | type ResourceMutationApplyConfiguration struct { 24 | Delete *ResourceDeleteMutationApplyConfiguration `json:"delete,omitempty"` 25 | Regex *ResourceRegexMutationApplyConfiguration `json:"regex,omitempty"` 26 | Template *ResourceTemplateMutationApplyConfiguration `json:"template,omitempty"` 27 | } 28 | 29 | // ResourceMutationApplyConfiguration constructs a declarative configuration of the ResourceMutation type for use with 30 | // apply. 31 | func ResourceMutation() *ResourceMutationApplyConfiguration { 32 | return &ResourceMutationApplyConfiguration{} 33 | } 34 | 35 | // WithDelete sets the Delete field in the declarative configuration to the given value 36 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 37 | // If called multiple times, the Delete field is set to the value of the last call. 38 | func (b *ResourceMutationApplyConfiguration) WithDelete(value *ResourceDeleteMutationApplyConfiguration) *ResourceMutationApplyConfiguration { 39 | b.Delete = value 40 | return b 41 | } 42 | 43 | // WithRegex sets the Regex field in the declarative configuration to the given value 44 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 45 | // If called multiple times, the Regex field is set to the value of the last call. 46 | func (b *ResourceMutationApplyConfiguration) WithRegex(value *ResourceRegexMutationApplyConfiguration) *ResourceMutationApplyConfiguration { 47 | b.Regex = value 48 | return b 49 | } 50 | 51 | // WithTemplate sets the Template field in the declarative configuration to the given value 52 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 53 | // If called multiple times, the Template field is set to the value of the last call. 54 | func (b *ResourceMutationApplyConfiguration) WithTemplate(value *ResourceTemplateMutationApplyConfiguration) *ResourceMutationApplyConfiguration { 55 | b.Template = value 56 | return b 57 | } 58 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourcemutationspec.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ResourceMutationSpecApplyConfiguration represents a declarative configuration of the ResourceMutationSpec type for use 22 | // with apply. 23 | type ResourceMutationSpecApplyConfiguration struct { 24 | Spec []ResourceMutationApplyConfiguration `json:"spec,omitempty"` 25 | Status []ResourceMutationApplyConfiguration `json:"status,omitempty"` 26 | } 27 | 28 | // ResourceMutationSpecApplyConfiguration constructs a declarative configuration of the ResourceMutationSpec type for use with 29 | // apply. 30 | func ResourceMutationSpec() *ResourceMutationSpecApplyConfiguration { 31 | return &ResourceMutationSpecApplyConfiguration{} 32 | } 33 | 34 | // WithSpec adds the given value to the Spec field in the declarative configuration 35 | // and returns the receiver, so that objects can be build by chaining "With" function invocations. 36 | // If called multiple times, values provided by each call will be appended to the Spec field. 37 | func (b *ResourceMutationSpecApplyConfiguration) WithSpec(values ...*ResourceMutationApplyConfiguration) *ResourceMutationSpecApplyConfiguration { 38 | for i := range values { 39 | if values[i] == nil { 40 | panic("nil value passed to WithSpec") 41 | } 42 | b.Spec = append(b.Spec, *values[i]) 43 | } 44 | return b 45 | } 46 | 47 | // WithStatus adds the given value to the Status field in the declarative configuration 48 | // and returns the receiver, so that objects can be build by chaining "With" function invocations. 49 | // If called multiple times, values provided by each call will be appended to the Status field. 50 | func (b *ResourceMutationSpecApplyConfiguration) WithStatus(values ...*ResourceMutationApplyConfiguration) *ResourceMutationSpecApplyConfiguration { 51 | for i := range values { 52 | if values[i] == nil { 53 | panic("nil value passed to WithStatus") 54 | } 55 | b.Status = append(b.Status, *values[i]) 56 | } 57 | return b 58 | } 59 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourcenaming.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ResourceNamingApplyConfiguration represents a declarative configuration of the ResourceNaming type for use 22 | // with apply. 23 | type ResourceNamingApplyConfiguration struct { 24 | Name *string `json:"name,omitempty"` 25 | Namespace *string `json:"namespace,omitempty"` 26 | } 27 | 28 | // ResourceNamingApplyConfiguration constructs a declarative configuration of the ResourceNaming type for use with 29 | // apply. 30 | func ResourceNaming() *ResourceNamingApplyConfiguration { 31 | return &ResourceNamingApplyConfiguration{} 32 | } 33 | 34 | // WithName sets the Name field in the declarative configuration to the given value 35 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 36 | // If called multiple times, the Name field is set to the value of the last call. 37 | func (b *ResourceNamingApplyConfiguration) WithName(value string) *ResourceNamingApplyConfiguration { 38 | b.Name = &value 39 | return b 40 | } 41 | 42 | // WithNamespace sets the Namespace field in the declarative configuration to the given value 43 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 44 | // If called multiple times, the Namespace field is set to the value of the last call. 45 | func (b *ResourceNamingApplyConfiguration) WithNamespace(value string) *ResourceNamingApplyConfiguration { 46 | b.Namespace = &value 47 | return b 48 | } 49 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourceregexmutation.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ResourceRegexMutationApplyConfiguration represents a declarative configuration of the ResourceRegexMutation type for use 22 | // with apply. 23 | type ResourceRegexMutationApplyConfiguration struct { 24 | Path *string `json:"path,omitempty"` 25 | Pattern *string `json:"pattern,omitempty"` 26 | Replacement *string `json:"replacement,omitempty"` 27 | } 28 | 29 | // ResourceRegexMutationApplyConfiguration constructs a declarative configuration of the ResourceRegexMutation type for use with 30 | // apply. 31 | func ResourceRegexMutation() *ResourceRegexMutationApplyConfiguration { 32 | return &ResourceRegexMutationApplyConfiguration{} 33 | } 34 | 35 | // WithPath sets the Path field in the declarative configuration to the given value 36 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 37 | // If called multiple times, the Path field is set to the value of the last call. 38 | func (b *ResourceRegexMutationApplyConfiguration) WithPath(value string) *ResourceRegexMutationApplyConfiguration { 39 | b.Path = &value 40 | return b 41 | } 42 | 43 | // WithPattern sets the Pattern field in the declarative configuration to the given value 44 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 45 | // If called multiple times, the Pattern field is set to the value of the last call. 46 | func (b *ResourceRegexMutationApplyConfiguration) WithPattern(value string) *ResourceRegexMutationApplyConfiguration { 47 | b.Pattern = &value 48 | return b 49 | } 50 | 51 | // WithReplacement sets the Replacement field in the declarative configuration to the given value 52 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 53 | // If called multiple times, the Replacement field is set to the value of the last call. 54 | func (b *ResourceRegexMutationApplyConfiguration) WithReplacement(value string) *ResourceRegexMutationApplyConfiguration { 55 | b.Replacement = &value 56 | return b 57 | } 58 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/resourcetemplatemutation.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // ResourceTemplateMutationApplyConfiguration represents a declarative configuration of the ResourceTemplateMutation type for use 22 | // with apply. 23 | type ResourceTemplateMutationApplyConfiguration struct { 24 | Path *string `json:"path,omitempty"` 25 | Template *string `json:"template,omitempty"` 26 | } 27 | 28 | // ResourceTemplateMutationApplyConfiguration constructs a declarative configuration of the ResourceTemplateMutation type for use with 29 | // apply. 30 | func ResourceTemplateMutation() *ResourceTemplateMutationApplyConfiguration { 31 | return &ResourceTemplateMutationApplyConfiguration{} 32 | } 33 | 34 | // WithPath sets the Path field in the declarative configuration to the given value 35 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 36 | // If called multiple times, the Path field is set to the value of the last call. 37 | func (b *ResourceTemplateMutationApplyConfiguration) WithPath(value string) *ResourceTemplateMutationApplyConfiguration { 38 | b.Path = &value 39 | return b 40 | } 41 | 42 | // WithTemplate sets the Template field in the declarative configuration to the given value 43 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 44 | // If called multiple times, the Template field is set to the value of the last call. 45 | func (b *ResourceTemplateMutationApplyConfiguration) WithTemplate(value string) *ResourceTemplateMutationApplyConfiguration { 46 | b.Template = &value 47 | return b 48 | } 49 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/sourceresourcedescriptor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // SourceResourceDescriptorApplyConfiguration represents a declarative configuration of the SourceResourceDescriptor type for use 22 | // with apply. 23 | type SourceResourceDescriptorApplyConfiguration struct { 24 | APIGroup *string `json:"apiGroup,omitempty"` 25 | Version *string `json:"version,omitempty"` 26 | Versions []string `json:"versions,omitempty"` 27 | Kind *string `json:"kind,omitempty"` 28 | } 29 | 30 | // SourceResourceDescriptorApplyConfiguration constructs a declarative configuration of the SourceResourceDescriptor type for use with 31 | // apply. 32 | func SourceResourceDescriptor() *SourceResourceDescriptorApplyConfiguration { 33 | return &SourceResourceDescriptorApplyConfiguration{} 34 | } 35 | 36 | // WithAPIGroup sets the APIGroup field in the declarative configuration to the given value 37 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 38 | // If called multiple times, the APIGroup field is set to the value of the last call. 39 | func (b *SourceResourceDescriptorApplyConfiguration) WithAPIGroup(value string) *SourceResourceDescriptorApplyConfiguration { 40 | b.APIGroup = &value 41 | return b 42 | } 43 | 44 | // WithVersion sets the Version field in the declarative configuration to the given value 45 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 46 | // If called multiple times, the Version field is set to the value of the last call. 47 | func (b *SourceResourceDescriptorApplyConfiguration) WithVersion(value string) *SourceResourceDescriptorApplyConfiguration { 48 | b.Version = &value 49 | return b 50 | } 51 | 52 | // WithVersions adds the given value to the Versions field in the declarative configuration 53 | // and returns the receiver, so that objects can be build by chaining "With" function invocations. 54 | // If called multiple times, values provided by each call will be appended to the Versions field. 55 | func (b *SourceResourceDescriptorApplyConfiguration) WithVersions(values ...string) *SourceResourceDescriptorApplyConfiguration { 56 | for i := range values { 57 | b.Versions = append(b.Versions, values[i]) 58 | } 59 | return b 60 | } 61 | 62 | // WithKind sets the Kind field in the declarative configuration to the given value 63 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 64 | // If called multiple times, the Kind field is set to the value of the last call. 65 | func (b *SourceResourceDescriptorApplyConfiguration) WithKind(value string) *SourceResourceDescriptorApplyConfiguration { 66 | b.Kind = &value 67 | return b 68 | } 69 | -------------------------------------------------------------------------------- /sdk/applyconfiguration/syncagent/v1alpha1/templateexpression.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by applyconfiguration-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | // TemplateExpressionApplyConfiguration represents a declarative configuration of the TemplateExpression type for use 22 | // with apply. 23 | type TemplateExpressionApplyConfiguration struct { 24 | Template *string `json:"template,omitempty"` 25 | } 26 | 27 | // TemplateExpressionApplyConfiguration constructs a declarative configuration of the TemplateExpression type for use with 28 | // apply. 29 | func TemplateExpression() *TemplateExpressionApplyConfiguration { 30 | return &TemplateExpressionApplyConfiguration{} 31 | } 32 | 33 | // WithTemplate sets the Template field in the declarative configuration to the given value 34 | // and returns the receiver, so that objects can be built by chaining "With" function invocations. 35 | // If called multiple times, the Template field is set to the value of the last call. 36 | func (b *TemplateExpressionApplyConfiguration) WithTemplate(value string) *TemplateExpressionApplyConfiguration { 37 | b.Template = &value 38 | return b 39 | } 40 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/cluster/scheme/register.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package scheme 23 | 24 | import ( 25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/apimachinery/pkg/runtime" 27 | "k8s.io/apimachinery/pkg/runtime/schema" 28 | "k8s.io/apimachinery/pkg/runtime/serializer" 29 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 30 | 31 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1" 32 | ) 33 | 34 | var Scheme = runtime.NewScheme() 35 | var Codecs = serializer.NewCodecFactory(Scheme) 36 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 37 | var localSchemeBuilder = runtime.SchemeBuilder{ 38 | syncagentv1alpha1.AddToScheme, 39 | } 40 | 41 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 42 | // of clientsets, like in: 43 | // 44 | // import ( 45 | // "k8s.io/client-go/kubernetes" 46 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 47 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 48 | // ) 49 | // 50 | // kclientset, _ := kubernetes.NewForConfig(c) 51 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 52 | // 53 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 54 | // correctly. 55 | var AddToScheme = localSchemeBuilder.AddToScheme 56 | 57 | func init() { 58 | metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 59 | utilruntime.Must(AddToScheme(Scheme)) 60 | } 61 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/cluster/typed/syncagent/v1alpha1/fake/syncagent_client.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package fake 23 | 24 | import ( 25 | "github.com/kcp-dev/logicalcluster/v3" 26 | 27 | kcptesting "github.com/kcp-dev/client-go/third_party/k8s.io/client-go/testing" 28 | "k8s.io/client-go/rest" 29 | 30 | kcpsyncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/cluster/typed/syncagent/v1alpha1" 31 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/typed/syncagent/v1alpha1" 32 | ) 33 | 34 | var _ kcpsyncagentv1alpha1.SyncagentV1alpha1ClusterInterface = (*SyncagentV1alpha1ClusterClient)(nil) 35 | 36 | type SyncagentV1alpha1ClusterClient struct { 37 | *kcptesting.Fake 38 | } 39 | 40 | func (c *SyncagentV1alpha1ClusterClient) Cluster(clusterPath logicalcluster.Path) syncagentv1alpha1.SyncagentV1alpha1Interface { 41 | if clusterPath == logicalcluster.Wildcard { 42 | panic("A specific cluster must be provided when scoping, not the wildcard.") 43 | } 44 | return &SyncagentV1alpha1Client{Fake: c.Fake, ClusterPath: clusterPath} 45 | } 46 | 47 | func (c *SyncagentV1alpha1ClusterClient) PublishedResources() kcpsyncagentv1alpha1.PublishedResourceClusterInterface { 48 | return &publishedResourcesClusterClient{Fake: c.Fake} 49 | } 50 | 51 | var _ syncagentv1alpha1.SyncagentV1alpha1Interface = (*SyncagentV1alpha1Client)(nil) 52 | 53 | type SyncagentV1alpha1Client struct { 54 | *kcptesting.Fake 55 | ClusterPath logicalcluster.Path 56 | } 57 | 58 | func (c *SyncagentV1alpha1Client) RESTClient() rest.Interface { 59 | var ret *rest.RESTClient 60 | return ret 61 | } 62 | 63 | func (c *SyncagentV1alpha1Client) PublishedResources() syncagentv1alpha1.PublishedResourceInterface { 64 | return &publishedResourcesClient{Fake: c.Fake, ClusterPath: c.ClusterPath} 65 | } 66 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/cluster/typed/syncagent/v1alpha1/publishedresource.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | import ( 25 | "context" 26 | 27 | kcpclient "github.com/kcp-dev/apimachinery/v2/pkg/client" 28 | "github.com/kcp-dev/logicalcluster/v3" 29 | 30 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 | "k8s.io/apimachinery/pkg/watch" 32 | 33 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1" 34 | syncagentv1alpha1client "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/typed/syncagent/v1alpha1" 35 | ) 36 | 37 | // PublishedResourcesClusterGetter has a method to return a PublishedResourceClusterInterface. 38 | // A group's cluster client should implement this interface. 39 | type PublishedResourcesClusterGetter interface { 40 | PublishedResources() PublishedResourceClusterInterface 41 | } 42 | 43 | // PublishedResourceClusterInterface can operate on PublishedResources across all clusters, 44 | // or scope down to one cluster and return a syncagentv1alpha1client.PublishedResourceInterface. 45 | type PublishedResourceClusterInterface interface { 46 | Cluster(logicalcluster.Path) syncagentv1alpha1client.PublishedResourceInterface 47 | List(ctx context.Context, opts metav1.ListOptions) (*syncagentv1alpha1.PublishedResourceList, error) 48 | Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) 49 | } 50 | 51 | type publishedResourcesClusterInterface struct { 52 | clientCache kcpclient.Cache[*syncagentv1alpha1client.SyncagentV1alpha1Client] 53 | } 54 | 55 | // Cluster scopes the client down to a particular cluster. 56 | func (c *publishedResourcesClusterInterface) Cluster(clusterPath logicalcluster.Path) syncagentv1alpha1client.PublishedResourceInterface { 57 | if clusterPath == logicalcluster.Wildcard { 58 | panic("A specific cluster must be provided when scoping, not the wildcard.") 59 | } 60 | 61 | return c.clientCache.ClusterOrDie(clusterPath).PublishedResources() 62 | } 63 | 64 | // List returns the entire collection of all PublishedResources across all clusters. 65 | func (c *publishedResourcesClusterInterface) List(ctx context.Context, opts metav1.ListOptions) (*syncagentv1alpha1.PublishedResourceList, error) { 66 | return c.clientCache.ClusterOrDie(logicalcluster.Wildcard).PublishedResources().List(ctx, opts) 67 | } 68 | 69 | // Watch begins to watch all PublishedResources across all clusters. 70 | func (c *publishedResourcesClusterInterface) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { 71 | return c.clientCache.ClusterOrDie(logicalcluster.Wildcard).PublishedResources().Watch(ctx, opts) 72 | } 73 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/cluster/typed/syncagent/v1alpha1/syncagent_client.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | import ( 25 | "net/http" 26 | 27 | kcpclient "github.com/kcp-dev/apimachinery/v2/pkg/client" 28 | "github.com/kcp-dev/logicalcluster/v3" 29 | 30 | "k8s.io/client-go/rest" 31 | 32 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/typed/syncagent/v1alpha1" 33 | ) 34 | 35 | type SyncagentV1alpha1ClusterInterface interface { 36 | SyncagentV1alpha1ClusterScoper 37 | PublishedResourcesClusterGetter 38 | } 39 | 40 | type SyncagentV1alpha1ClusterScoper interface { 41 | Cluster(logicalcluster.Path) syncagentv1alpha1.SyncagentV1alpha1Interface 42 | } 43 | 44 | type SyncagentV1alpha1ClusterClient struct { 45 | clientCache kcpclient.Cache[*syncagentv1alpha1.SyncagentV1alpha1Client] 46 | } 47 | 48 | func (c *SyncagentV1alpha1ClusterClient) Cluster(clusterPath logicalcluster.Path) syncagentv1alpha1.SyncagentV1alpha1Interface { 49 | if clusterPath == logicalcluster.Wildcard { 50 | panic("A specific cluster must be provided when scoping, not the wildcard.") 51 | } 52 | return c.clientCache.ClusterOrDie(clusterPath) 53 | } 54 | 55 | func (c *SyncagentV1alpha1ClusterClient) PublishedResources() PublishedResourceClusterInterface { 56 | return &publishedResourcesClusterInterface{clientCache: c.clientCache} 57 | } 58 | 59 | // NewForConfig creates a new SyncagentV1alpha1ClusterClient for the given config. 60 | // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), 61 | // where httpClient was generated with rest.HTTPClientFor(c). 62 | func NewForConfig(c *rest.Config) (*SyncagentV1alpha1ClusterClient, error) { 63 | client, err := rest.HTTPClientFor(c) 64 | if err != nil { 65 | return nil, err 66 | } 67 | return NewForConfigAndClient(c, client) 68 | } 69 | 70 | // NewForConfigAndClient creates a new SyncagentV1alpha1ClusterClient for the given config and http client. 71 | // Note the http client provided takes precedence over the configured transport values. 72 | func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SyncagentV1alpha1ClusterClient, error) { 73 | cache := kcpclient.NewCache(c, h, &kcpclient.Constructor[*syncagentv1alpha1.SyncagentV1alpha1Client]{ 74 | NewForConfigAndClient: syncagentv1alpha1.NewForConfigAndClient, 75 | }) 76 | if _, err := cache.Cluster(logicalcluster.Name("root").Path()); err != nil { 77 | return nil, err 78 | } 79 | return &SyncagentV1alpha1ClusterClient{clientCache: cache}, nil 80 | } 81 | 82 | // NewForConfigOrDie creates a new SyncagentV1alpha1ClusterClient for the given config and 83 | // panics if there is an error in the config. 84 | func NewForConfigOrDie(c *rest.Config) *SyncagentV1alpha1ClusterClient { 85 | client, err := NewForConfig(c) 86 | if err != nil { 87 | panic(err) 88 | } 89 | return client 90 | } 91 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/fake/clientset_generated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | "k8s.io/apimachinery/pkg/runtime" 23 | "k8s.io/apimachinery/pkg/watch" 24 | "k8s.io/client-go/discovery" 25 | fakediscovery "k8s.io/client-go/discovery/fake" 26 | "k8s.io/client-go/testing" 27 | 28 | clientset "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned" 29 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/typed/syncagent/v1alpha1" 30 | fakesyncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/typed/syncagent/v1alpha1/fake" 31 | ) 32 | 33 | // NewSimpleClientset returns a clientset that will respond with the provided objects. 34 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, 35 | // without applying any field management, validations and/or defaults. It shouldn't be considered a replacement 36 | // for a real clientset and is mostly useful in simple unit tests. 37 | // 38 | // DEPRECATED: NewClientset replaces this with support for field management, which significantly improves 39 | // server side apply testing. NewClientset is only available when apply configurations are generated (e.g. 40 | // via --with-applyconfig). 41 | func NewSimpleClientset(objects ...runtime.Object) *Clientset { 42 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) 43 | for _, obj := range objects { 44 | if err := o.Add(obj); err != nil { 45 | panic(err) 46 | } 47 | } 48 | 49 | cs := &Clientset{tracker: o} 50 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} 51 | cs.AddReactor("*", "*", testing.ObjectReaction(o)) 52 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { 53 | gvr := action.GetResource() 54 | ns := action.GetNamespace() 55 | watch, err := o.Watch(gvr, ns) 56 | if err != nil { 57 | return false, nil, err 58 | } 59 | return true, watch, nil 60 | }) 61 | 62 | return cs 63 | } 64 | 65 | // Clientset implements clientset.Interface. Meant to be embedded into a 66 | // struct to get a default implementation. This makes faking out just the method 67 | // you want to test easier. 68 | type Clientset struct { 69 | testing.Fake 70 | discovery *fakediscovery.FakeDiscovery 71 | tracker testing.ObjectTracker 72 | } 73 | 74 | func (c *Clientset) Discovery() discovery.DiscoveryInterface { 75 | return c.discovery 76 | } 77 | 78 | func (c *Clientset) Tracker() testing.ObjectTracker { 79 | return c.tracker 80 | } 81 | 82 | var ( 83 | _ clientset.Interface = &Clientset{} 84 | _ testing.FakeClient = &Clientset{} 85 | ) 86 | 87 | // SyncagentV1alpha1 retrieves the SyncagentV1alpha1Client 88 | func (c *Clientset) SyncagentV1alpha1() syncagentv1alpha1.SyncagentV1alpha1Interface { 89 | return &fakesyncagentv1alpha1.FakeSyncagentV1alpha1{Fake: &c.Fake} 90 | } 91 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated fake clientset. 20 | package fake 21 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/fake/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | runtime "k8s.io/apimachinery/pkg/runtime" 24 | schema "k8s.io/apimachinery/pkg/runtime/schema" 25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 27 | 28 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1" 29 | ) 30 | 31 | var scheme = runtime.NewScheme() 32 | var codecs = serializer.NewCodecFactory(scheme) 33 | 34 | var localSchemeBuilder = runtime.SchemeBuilder{ 35 | syncagentv1alpha1.AddToScheme, 36 | } 37 | 38 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 39 | // of clientsets, like in: 40 | // 41 | // import ( 42 | // "k8s.io/client-go/kubernetes" 43 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 44 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 45 | // ) 46 | // 47 | // kclientset, _ := kubernetes.NewForConfig(c) 48 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 49 | // 50 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 51 | // correctly. 52 | var AddToScheme = localSchemeBuilder.AddToScheme 53 | 54 | func init() { 55 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) 56 | utilruntime.Must(AddToScheme(scheme)) 57 | } 58 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/scheme/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package contains the scheme of the automatically generated clientset. 20 | package scheme 21 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/scheme/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package scheme 20 | 21 | import ( 22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | runtime "k8s.io/apimachinery/pkg/runtime" 24 | schema "k8s.io/apimachinery/pkg/runtime/schema" 25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer" 26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 27 | 28 | syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1" 29 | ) 30 | 31 | var Scheme = runtime.NewScheme() 32 | var Codecs = serializer.NewCodecFactory(Scheme) 33 | var ParameterCodec = runtime.NewParameterCodec(Scheme) 34 | var localSchemeBuilder = runtime.SchemeBuilder{ 35 | syncagentv1alpha1.AddToScheme, 36 | } 37 | 38 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition 39 | // of clientsets, like in: 40 | // 41 | // import ( 42 | // "k8s.io/client-go/kubernetes" 43 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme" 44 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" 45 | // ) 46 | // 47 | // kclientset, _ := kubernetes.NewForConfig(c) 48 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) 49 | // 50 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types 51 | // correctly. 52 | var AddToScheme = localSchemeBuilder.AddToScheme 53 | 54 | func init() { 55 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 56 | utilruntime.Must(AddToScheme(Scheme)) 57 | } 58 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/typed/syncagent/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // This package has the automatically generated typed clients. 20 | package v1alpha1 21 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/typed/syncagent/v1alpha1/fake/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | // Package fake has the automatically generated clients. 20 | package fake 21 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/typed/syncagent/v1alpha1/fake/fake_syncagent_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package fake 20 | 21 | import ( 22 | rest "k8s.io/client-go/rest" 23 | testing "k8s.io/client-go/testing" 24 | 25 | v1alpha1 "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/typed/syncagent/v1alpha1" 26 | ) 27 | 28 | type FakeSyncagentV1alpha1 struct { 29 | *testing.Fake 30 | } 31 | 32 | func (c *FakeSyncagentV1alpha1) PublishedResources() v1alpha1.PublishedResourceInterface { 33 | return &FakePublishedResources{c} 34 | } 35 | 36 | // RESTClient returns a RESTClient that is used to communicate 37 | // with API server by this client implementation. 38 | func (c *FakeSyncagentV1alpha1) RESTClient() rest.Interface { 39 | var ret *rest.RESTClient 40 | return ret 41 | } 42 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/typed/syncagent/v1alpha1/generated_expansion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | type PublishedResourceExpansion interface{} 22 | -------------------------------------------------------------------------------- /sdk/clientset/versioned/typed/syncagent/v1alpha1/publishedresource.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Code generated by client-gen. DO NOT EDIT. 18 | 19 | package v1alpha1 20 | 21 | import ( 22 | "context" 23 | 24 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 | types "k8s.io/apimachinery/pkg/types" 26 | watch "k8s.io/apimachinery/pkg/watch" 27 | gentype "k8s.io/client-go/gentype" 28 | 29 | v1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1" 30 | scheme "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/scheme" 31 | ) 32 | 33 | // PublishedResourcesGetter has a method to return a PublishedResourceInterface. 34 | // A group's client should implement this interface. 35 | type PublishedResourcesGetter interface { 36 | PublishedResources() PublishedResourceInterface 37 | } 38 | 39 | // PublishedResourceInterface has methods to work with PublishedResource resources. 40 | type PublishedResourceInterface interface { 41 | Create(ctx context.Context, publishedResource *v1alpha1.PublishedResource, opts v1.CreateOptions) (*v1alpha1.PublishedResource, error) 42 | Update(ctx context.Context, publishedResource *v1alpha1.PublishedResource, opts v1.UpdateOptions) (*v1alpha1.PublishedResource, error) 43 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). 44 | UpdateStatus(ctx context.Context, publishedResource *v1alpha1.PublishedResource, opts v1.UpdateOptions) (*v1alpha1.PublishedResource, error) 45 | Delete(ctx context.Context, name string, opts v1.DeleteOptions) error 46 | DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error 47 | Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.PublishedResource, error) 48 | List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.PublishedResourceList, error) 49 | Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) 50 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.PublishedResource, err error) 51 | PublishedResourceExpansion 52 | } 53 | 54 | // publishedResources implements PublishedResourceInterface 55 | type publishedResources struct { 56 | *gentype.ClientWithList[*v1alpha1.PublishedResource, *v1alpha1.PublishedResourceList] 57 | } 58 | 59 | // newPublishedResources returns a PublishedResources 60 | func newPublishedResources(c *SyncagentV1alpha1Client) *publishedResources { 61 | return &publishedResources{ 62 | gentype.NewClientWithList[*v1alpha1.PublishedResource, *v1alpha1.PublishedResourceList]( 63 | "publishedresources", 64 | c.RESTClient(), 65 | scheme.ParameterCodec, 66 | "", 67 | func() *v1alpha1.PublishedResource { return &v1alpha1.PublishedResource{} }, 68 | func() *v1alpha1.PublishedResourceList { return &v1alpha1.PublishedResourceList{} }), 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sdk/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kcp-dev/api-syncagent/sdk 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/kcp-dev/apimachinery/v2 v2.0.1-0.20250223115924-431177b024f3 7 | github.com/kcp-dev/client-go v0.0.0-20250223133118-3dea338dc267 8 | github.com/kcp-dev/logicalcluster/v3 v3.0.5 9 | k8s.io/apimachinery v0.31.6 10 | k8s.io/client-go v0.31.6 11 | sigs.k8s.io/structured-merge-diff/v4 v4.6.0 12 | ) 13 | 14 | require ( 15 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 16 | github.com/emicklei/go-restful/v3 v3.12.2 // indirect 17 | github.com/evanphx/json-patch v5.9.11+incompatible // indirect 18 | github.com/fxamacker/cbor/v2 v2.8.0 // indirect 19 | github.com/go-logr/logr v1.4.2 // indirect 20 | github.com/go-openapi/jsonpointer v0.21.1 // indirect 21 | github.com/go-openapi/jsonreference v0.21.0 // indirect 22 | github.com/go-openapi/swag v0.23.1 // indirect 23 | github.com/gogo/protobuf v1.3.2 // indirect 24 | github.com/golang/protobuf v1.5.4 // indirect 25 | github.com/google/gnostic-models v0.6.9 // indirect 26 | github.com/google/go-cmp v0.7.0 // indirect 27 | github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea // indirect 28 | github.com/google/uuid v1.6.0 // indirect 29 | github.com/josharian/intern v1.0.0 // indirect 30 | github.com/json-iterator/go v1.1.12 // indirect 31 | github.com/mailru/easyjson v0.9.0 // indirect 32 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 33 | github.com/modern-go/reflect2 v1.0.2 // indirect 34 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 35 | github.com/onsi/ginkgo/v2 v2.23.3 // indirect 36 | github.com/onsi/gomega v1.36.3 // indirect 37 | github.com/pkg/errors v0.9.1 // indirect 38 | github.com/rogpeppe/go-internal v1.13.1 // indirect 39 | github.com/spf13/pflag v1.0.6 // indirect 40 | github.com/x448/float16 v0.8.4 // indirect 41 | golang.org/x/net v0.38.0 // indirect 42 | golang.org/x/oauth2 v0.28.0 // indirect 43 | golang.org/x/sys v0.31.0 // indirect 44 | golang.org/x/term v0.30.0 // indirect 45 | golang.org/x/text v0.23.0 // indirect 46 | golang.org/x/time v0.11.0 // indirect 47 | golang.org/x/tools v0.31.0 // indirect 48 | google.golang.org/protobuf v1.36.6 // indirect 49 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 50 | gopkg.in/inf.v0 v0.9.1 // indirect 51 | gopkg.in/yaml.v2 v2.4.0 // indirect 52 | gopkg.in/yaml.v3 v3.0.1 // indirect 53 | k8s.io/api v0.31.6 // indirect 54 | k8s.io/klog/v2 v2.130.1 // indirect 55 | k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect 56 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect 57 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 58 | sigs.k8s.io/yaml v1.4.0 // indirect 59 | ) 60 | -------------------------------------------------------------------------------- /sdk/informers/externalversions/internalinterfaces/factory_interfaces.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package internalinterfaces 23 | 24 | import ( 25 | time "time" 26 | 27 | kcpcache "github.com/kcp-dev/apimachinery/v2/pkg/cache" 28 | 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | runtime "k8s.io/apimachinery/pkg/runtime" 31 | "k8s.io/client-go/tools/cache" 32 | 33 | scopedclientset "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned" 34 | clientset "github.com/kcp-dev/api-syncagent/sdk/clientset/versioned/cluster" 35 | ) 36 | 37 | // NewInformerFunc takes clientset.ClusterInterface and time.Duration to return a ScopeableSharedIndexInformer. 38 | type NewInformerFunc func(clientset.ClusterInterface, time.Duration) kcpcache.ScopeableSharedIndexInformer 39 | 40 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle 41 | type SharedInformerFactory interface { 42 | Start(stopCh <-chan struct{}) 43 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) kcpcache.ScopeableSharedIndexInformer 44 | } 45 | 46 | // NewScopedInformerFunc takes scopedclientset.Interface and time.Duration to return a SharedIndexInformer. 47 | type NewScopedInformerFunc func(scopedclientset.Interface, time.Duration) cache.SharedIndexInformer 48 | 49 | // SharedScopedInformerFactory a small interface to allow for adding an informer without an import cycle 50 | type SharedScopedInformerFactory interface { 51 | Start(stopCh <-chan struct{}) 52 | InformerFor(obj runtime.Object, newFunc NewScopedInformerFunc) cache.SharedIndexInformer 53 | } 54 | 55 | // TweakListOptionsFunc is a function that transforms a metav1.ListOptions. 56 | type TweakListOptionsFunc func(*metav1.ListOptions) 57 | -------------------------------------------------------------------------------- /sdk/informers/externalversions/syncagent/interface.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package syncagent 23 | 24 | import ( 25 | "github.com/kcp-dev/api-syncagent/sdk/informers/externalversions/internalinterfaces" 26 | "github.com/kcp-dev/api-syncagent/sdk/informers/externalversions/syncagent/v1alpha1" 27 | ) 28 | 29 | type ClusterInterface interface { 30 | // V1alpha1 provides access to the shared informers in V1alpha1. 31 | V1alpha1() v1alpha1.ClusterInterface 32 | } 33 | 34 | type group struct { 35 | factory internalinterfaces.SharedInformerFactory 36 | tweakListOptions internalinterfaces.TweakListOptionsFunc 37 | } 38 | 39 | // New returns a new ClusterInterface. 40 | func New(f internalinterfaces.SharedInformerFactory, tweakListOptions internalinterfaces.TweakListOptionsFunc) ClusterInterface { 41 | return &group{factory: f, tweakListOptions: tweakListOptions} 42 | } 43 | 44 | // V1alpha1 returns a new v1alpha1.ClusterInterface. 45 | func (g *group) V1alpha1() v1alpha1.ClusterInterface { 46 | return v1alpha1.New(g.factory, g.tweakListOptions) 47 | } 48 | 49 | type Interface interface { 50 | // V1alpha1 provides access to the shared informers in V1alpha1. 51 | V1alpha1() v1alpha1.Interface 52 | } 53 | 54 | type scopedGroup struct { 55 | factory internalinterfaces.SharedScopedInformerFactory 56 | tweakListOptions internalinterfaces.TweakListOptionsFunc 57 | namespace string 58 | } 59 | 60 | // New returns a new Interface. 61 | func NewScoped(f internalinterfaces.SharedScopedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 62 | return &scopedGroup{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 63 | } 64 | 65 | // V1alpha1 returns a new v1alpha1.ClusterInterface. 66 | func (g *scopedGroup) V1alpha1() v1alpha1.Interface { 67 | return v1alpha1.NewScoped(g.factory, g.namespace, g.tweakListOptions) 68 | } 69 | -------------------------------------------------------------------------------- /sdk/informers/externalversions/syncagent/v1alpha1/interface.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | import ( 25 | "github.com/kcp-dev/api-syncagent/sdk/informers/externalversions/internalinterfaces" 26 | ) 27 | 28 | type ClusterInterface interface { 29 | // PublishedResources returns a PublishedResourceClusterInformer 30 | PublishedResources() PublishedResourceClusterInformer 31 | } 32 | 33 | type version struct { 34 | factory internalinterfaces.SharedInformerFactory 35 | tweakListOptions internalinterfaces.TweakListOptionsFunc 36 | } 37 | 38 | // New returns a new ClusterInterface. 39 | func New(f internalinterfaces.SharedInformerFactory, tweakListOptions internalinterfaces.TweakListOptionsFunc) ClusterInterface { 40 | return &version{factory: f, tweakListOptions: tweakListOptions} 41 | } 42 | 43 | // PublishedResources returns a PublishedResourceClusterInformer 44 | func (v *version) PublishedResources() PublishedResourceClusterInformer { 45 | return &publishedResourceClusterInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} 46 | } 47 | 48 | type Interface interface { 49 | // PublishedResources returns a PublishedResourceInformer 50 | PublishedResources() PublishedResourceInformer 51 | } 52 | 53 | type scopedVersion struct { 54 | factory internalinterfaces.SharedScopedInformerFactory 55 | tweakListOptions internalinterfaces.TweakListOptionsFunc 56 | namespace string 57 | } 58 | 59 | // New returns a new ClusterInterface. 60 | func NewScoped(f internalinterfaces.SharedScopedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { 61 | return &scopedVersion{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} 62 | } 63 | 64 | // PublishedResources returns a PublishedResourceInformer 65 | func (v *scopedVersion) PublishedResources() PublishedResourceInformer { 66 | return &publishedResourceScopedInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} 67 | } 68 | -------------------------------------------------------------------------------- /sdk/listers/syncagent/v1alpha1/publishedresource_expansion.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The KCP Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by kcp code-generator. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | // PublishedResourceClusterListerExpansion allows custom methods to be added to PublishedResourceClusterLister. 25 | type PublishedResourceClusterListerExpansion interface{} 26 | 27 | // PublishedResourceListerExpansion allows custom methods to be added to PublishedResourceLister. 28 | type PublishedResourceListerExpansion interface{} 29 | -------------------------------------------------------------------------------- /test/crds/backup.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package crds 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type Backup struct { 24 | metav1.TypeMeta `json:",inline"` 25 | metav1.ObjectMeta `json:"metadata,omitempty"` 26 | 27 | Spec BackupSpec `json:"spec"` 28 | } 29 | 30 | type BackupSpec struct { 31 | Source string `json:"source"` 32 | Destination string `json:"destination"` 33 | } 34 | -------------------------------------------------------------------------------- /test/crds/backup.yaml: -------------------------------------------------------------------------------- 1 | # sourced from https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: backups.eksempel.no 6 | spec: 7 | group: eksempel.no 8 | scope: Namespaced 9 | names: 10 | plural: backups 11 | singular: backup 12 | kind: Backup 13 | versions: 14 | - name: v1 15 | served: true 16 | storage: true 17 | schema: 18 | openAPIV3Schema: 19 | type: object 20 | properties: 21 | spec: 22 | type: object 23 | properties: 24 | source: 25 | type: string 26 | destination: 27 | type: string 28 | -------------------------------------------------------------------------------- /test/crds/crontab-improved.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: crontabs.example.com 5 | spec: 6 | group: example.com 7 | scope: Namespaced 8 | names: 9 | plural: crontabs 10 | singular: crontab 11 | kind: CronTab 12 | shortNames: 13 | - ct 14 | versions: 15 | - name: v1 16 | served: true 17 | storage: true 18 | schema: 19 | openAPIV3Schema: 20 | type: object 21 | properties: 22 | spec: 23 | type: object 24 | properties: 25 | cronSpec: 26 | type: string 27 | image: 28 | type: string 29 | command: 30 | type: string 31 | replicas: 32 | type: integer 33 | -------------------------------------------------------------------------------- /test/crds/crontab-multi-versions.yaml: -------------------------------------------------------------------------------- 1 | # sourced from https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: crontabs.example.com 6 | spec: 7 | group: example.com 8 | scope: Namespaced 9 | names: 10 | plural: crontabs 11 | singular: crontab 12 | kind: CronTab 13 | shortNames: 14 | - ct 15 | versions: 16 | - name: v1 17 | served: true 18 | storage: false 19 | schema: 20 | openAPIV3Schema: 21 | type: object 22 | properties: 23 | spec: 24 | type: object 25 | properties: 26 | cronSpec: 27 | type: string 28 | image: 29 | type: string 30 | replicas: 31 | type: integer 32 | - name: v2 33 | served: true 34 | storage: true 35 | schema: 36 | openAPIV3Schema: 37 | type: object 38 | properties: 39 | spec: 40 | type: object 41 | properties: 42 | cronSpec: 43 | type: string 44 | image: 45 | type: string 46 | replicas: 47 | type: integer 48 | -------------------------------------------------------------------------------- /test/crds/crontab.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package crds 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type Crontab struct { 24 | metav1.TypeMeta `json:",inline"` 25 | metav1.ObjectMeta `json:"metadata,omitempty"` 26 | 27 | Spec CrontabSpec `json:"spec"` 28 | } 29 | 30 | type CrontabSpec struct { 31 | CronSpec string `json:"cronSpec"` 32 | Image string `json:"image"` 33 | Replicas int `json:"replicas"` 34 | } 35 | -------------------------------------------------------------------------------- /test/crds/crontab.yaml: -------------------------------------------------------------------------------- 1 | # sourced from https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: crontabs.example.com 6 | spec: 7 | group: example.com 8 | scope: Namespaced 9 | names: 10 | plural: crontabs 11 | singular: crontab 12 | kind: CronTab 13 | shortNames: 14 | - ct 15 | versions: 16 | - name: v1 17 | served: true 18 | storage: true 19 | schema: 20 | openAPIV3Schema: 21 | type: object 22 | properties: 23 | spec: 24 | type: object 25 | properties: 26 | cronSpec: 27 | type: string 28 | image: 29 | type: string 30 | replicas: 31 | type: integer 32 | -------------------------------------------------------------------------------- /test/utils/wait.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The KCP Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package utils 18 | 19 | import ( 20 | "context" 21 | "slices" 22 | "testing" 23 | "time" 24 | 25 | kcpapisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1" 26 | 27 | "k8s.io/apimachinery/pkg/runtime/schema" 28 | "k8s.io/apimachinery/pkg/types" 29 | "k8s.io/apimachinery/pkg/util/wait" 30 | ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client" 31 | ) 32 | 33 | func WaitForObject(t *testing.T, ctx context.Context, client ctrlruntimeclient.Client, obj ctrlruntimeclient.Object, key types.NamespacedName) { 34 | t.Helper() 35 | t.Logf("Waiting for %T to exist…", obj) 36 | 37 | err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 3*time.Minute, false, func(ctx context.Context) (done bool, err error) { 38 | err = client.Get(ctx, key, obj) 39 | return err == nil, nil 40 | }) 41 | if err != nil { 42 | t.Fatalf("Failed to wait for %T to exist: %v", obj, err) 43 | } 44 | 45 | t.Logf("%T is ready.", obj) 46 | } 47 | 48 | func WaitForBoundAPI(t *testing.T, ctx context.Context, client ctrlruntimeclient.Client, gvr schema.GroupVersionResource) { 49 | t.Helper() 50 | 51 | t.Log("Waiting for API to be bound in kcp…") 52 | err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 1*time.Minute, false, func(ctx context.Context) (bool, error) { 53 | apiBindings := &kcpapisv1alpha1.APIBindingList{} 54 | err := client.List(ctx, apiBindings) 55 | if err != nil { 56 | return false, err 57 | } 58 | 59 | for _, binding := range apiBindings.Items { 60 | if bindingHasGVR(binding, gvr) { 61 | return true, nil 62 | } 63 | } 64 | 65 | return false, nil 66 | }) 67 | if err != nil { 68 | t.Fatalf("Failed to wait for API %v to become available: %v", gvr, err) 69 | } 70 | } 71 | 72 | func bindingHasGVR(binding kcpapisv1alpha1.APIBinding, gvr schema.GroupVersionResource) bool { 73 | for _, bound := range binding.Status.BoundResources { 74 | if bound.Group == gvr.Group && bound.Resource == gvr.Resource && slices.Contains(bound.StorageVersions, gvr.Version) { 75 | return true 76 | } 77 | } 78 | 79 | return false 80 | } 81 | --------------------------------------------------------------------------------