Compare commits

..

6 Commits

Author SHA1 Message Date
t.behrendt 83630702b9 ci: modernize cicd
CD / Create tag (pull_request) Successful in 7s
CI / image check (pull_request) Successful in 5s
CD / build_and_push_image (pull_request) Successful in 24s
CI / install-dependencies (pull_request) Successful in 1m50s
CI / check format (pull_request) Successful in 23s
CI / check lint (pull_request) Successful in 22s
CI / build check (pull_request) Successful in 1m47s
CI / test (pull_request) Successful in 15m23s
2026-05-26 20:34:55 +02:00
t.behrendt 26bd576690 feat: vertical slice application -> provider -> binding (#4)
CD / Create tag (push) Successful in 11s
CD / Build and push (amd64) (push) Successful in 1m32s
CD / Create manifest (push) Successful in 7s
Co-authored-by: Timo Behrendt <t.behrendt@t00n.de>
Co-committed-by: Timo Behrendt <t.behrendt@t00n.de>
2026-05-25 17:14:35 +02:00
t.behrendt 2a091df8b9 ci: fix Makefile test (#10)
CD / Build and push (amd64) (push) Successful in 1m31s
CD / Create tag (push) Successful in 12s
CD / Create manifest (push) Successful in 19s
Reviewed-on: #10
Co-authored-by: Timo Behrendt <t.behrendt@t00n.de>
Co-committed-by: Timo Behrendt <t.behrendt@t00n.de>
2026-05-25 13:21:26 +02:00
renovate-bot 5219457d33 chore(deps): update gcr.io/distroless/static-debian12 docker digest to 9c346e4 (#5)
CD / Create tag (push) Successful in 21s
CD / Build and push (amd64) (push) Successful in 1m29s
CD / Create manifest (push) Successful in 52s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| gcr.io/distroless/static-debian12 | final | digest | `20bc6c0` → `9c346e4` |

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My41LjQiLCJ1cGRhdGVkSW5WZXIiOiI0My41LjQiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Reviewed-on: #5
Reviewed-by: t.behrendt <t.behrendt@noreply.localhost>
Co-authored-by: Renovate Bot <renovate@t00n.de>
Co-committed-by: Renovate Bot <renovate@t00n.de>
2026-05-19 10:41:47 +02:00
renovate-bot 2d26cd82d1 chore(deps): update kubernetes packages to v0.36.0 (#6)
CD / Create tag (push) Successful in 12s
CD / Build and push (amd64) (push) Successful in 1m30s
CD / Create manifest (push) Successful in 24s
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [k8s.io/api](https://github.com/kubernetes/api) | `v0.0.0-20260509204538-0dfb117cc6ec` → `v0.36.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/k8s.io%2fapi/v0.36.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/k8s.io%2fapi/v0.0.0-20260509204538-0dfb117cc6ec/v0.36.0?slim=true) |
| [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `v0.0.0-20260513183604-f9371b815e42` → `v0.36.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/k8s.io%2fapimachinery/v0.36.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/k8s.io%2fapimachinery/v0.0.0-20260513183604-f9371b815e42/v0.36.0?slim=true) |
| [k8s.io/client-go](https://github.com/kubernetes/client-go) | `v0.0.0-20260509205101-ca52b81a2940` → `v0.36.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/k8s.io%2fclient-go/v0.36.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/k8s.io%2fclient-go/v0.0.0-20260509205101-ca52b81a2940/v0.36.0?slim=true) |

Co-authored-by: Renovate Bot <renovate@t00n.de>
Co-committed-by: Renovate Bot <renovate@t00n.de>
2026-05-19 10:37:38 +02:00
t.behrendt bc8e7e10e1 feat: adjust sample to mvp (#1)
CD / Create tag (push) Successful in 12s
CD / Build and push (amd64) (push) Successful in 1m38s
CD / Create manifest (push) Successful in 7s
Reviewed-on: #1
Co-authored-by: Timo Behrendt <t.behrendt@t00n.de>
Co-committed-by: Timo Behrendt <t.behrendt@t00n.de>
2026-05-17 14:39:46 +02:00
109 changed files with 6573 additions and 1807 deletions
+8
View File
@@ -0,0 +1,8 @@
*
!pkg
!internal
!controller.go
!main.go
!go.mod
!go.sum
+16
View File
@@ -0,0 +1,16 @@
name: Go Cache Key
description: Create a cache key for Go dependencies
outputs:
hash:
description: The cache key for Go dependencies
value: ${{ steps.hash-go.outputs.hash }}
runs:
using: composite
steps:
- name: Create cache key
shell: bash
id: hash-go
run: |
echo "hash=$(sha256sum go.mod go.sum | sha256sum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
+51
View File
@@ -0,0 +1,51 @@
name: CD
on:
push:
branches:
- main
paths:
- "go.mod"
- "go.sum"
- "**/*.go"
- "Dockerfile"
- "Makefile"
pull_request:
branches:
- main
workflow_dispatch:
env:
DOCKER_REGISTRY: gitea.t000-n.de
jobs:
create_tag:
name: Create tag
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.tag.outputs.new-tag }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: https://gitea.t000-n.de/t.behrendt/conventional-semantic-git-tag-increment@ef0c23189db33220a73022d8c29a27709d0df440 # 0.1.32
id: tag
with:
token: ${{ secrets.GITEA_TOKEN }}
prerelease: ${{ github.event_name == 'workflow_dispatch' }}
- run: |
git tag ${{ steps.tag.outputs.new-tag }}
git push origin ${{ steps.tag.outputs.new-tag }}
- name: Set output
run: |
echo "tag=${{ steps.tag.outputs.new-tag }}" >> $GITHUB_OUTPUT
build_and_push_image:
needs: create_tag
uses: https://gitea.t000-n.de/t.behrendt/gitea-workflows/.gitea/workflows/build-container.yaml@0.1.1
with:
registry: gitea.t000-n.de/t.behrendt
registry-user: ${{ secrets.REGISTRY_USER }}
registry-password: ${{ secrets.REGISTRY_PASSWORD }}
repo-name: authentik-kubernetes-operator
tag: ${{ needs.create_tag.outputs.tag }}
+34 -20
View File
@@ -8,30 +8,44 @@ env:
RUNNER_TOOL_CACHE: /toolcache RUNNER_TOOL_CACHE: /toolcache
jobs: jobs:
install-dependencies:
uses: ./.gitea/workflows/install-go-dependencies.yaml
build-check:
name: build check
needs: install-dependencies
uses: ./.gitea/workflows/run-go-script.yaml
with:
script: build
check-format:
name: check format
needs: install-dependencies
uses: ./.gitea/workflows/run-go-script.yaml
with:
script: check-format
check-lint:
name: check lint
needs: install-dependencies
uses: ./.gitea/workflows/run-go-script.yaml
with:
script: lint
test: test:
name: test name: test
needs: install-dependencies
uses: ./.gitea/workflows/run-go-script.yaml
with:
script: test
image-check:
name: image check
runs-on: runs-on:
- ubuntu-latest - ubuntu-latest
- linux_amd64
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup go - name: Build image
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 run: make build-image
with:
go-version-file: go.mod
check-latest: true
- name: Create cache key
id: hash-go
run: echo "hash=$(sha256sum go.mod go.sum | sha256sum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
- name: cache go
id: cache-go
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
restore-keys: |-
go_cache-${{ steps.hash-go.outputs.hash }}
- name: build
run: make build
@@ -0,0 +1,33 @@
name: Install Go Dependencies
on:
workflow_call:
jobs:
install-dependencies:
runs-on:
- ubuntu-latest
- linux_amd64
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
- name: Create cache key
id: go-cache-key
uses: ./.gitea/actions/go-cache-key
- name: cache go
id: cache-go
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
/go_path
/go_cache
key: go_path-${{ steps.go-cache-key.outputs.hash }}
restore-keys: |-
go_cache-${{ steps.go-cache-key.outputs.hash }}
- name: Download dependencies
run: go mod download
+38
View File
@@ -0,0 +1,38 @@
name: Run Go Script
on:
workflow_call:
inputs:
script:
description: The script to run
required: true
type: string
jobs:
run-script:
runs-on:
- ubuntu-latest
- linux_amd64
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: go.mod
check-latest: true
- name: Create cache key
id: go-cache-key
uses: ./.gitea/actions/go-cache-key
- name: Install dependencies from Cache
id: cache-go
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
/go_path
/go_cache
key: go_path-${{ steps.go-cache-key.outputs.hash }}
restore-keys: |-
go_cache-${{ steps.go-cache-key.outputs.hash }}
- name: Run script
run: make ${{ inputs.script }}
+7
View File
@@ -14,6 +14,7 @@
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
lcov.info
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
@@ -25,3 +26,9 @@ go.work.sum
# env file # env file
.env .env
# vendor directory
vendor/
# build artifacts
main
__debug_bin*
+3
View File
@@ -0,0 +1,3 @@
[submodule "code-generator"]
path = code-generator
url = https://github.com/kubernetes/code-generator.git
+14
View File
@@ -0,0 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": ["--kubeconfig=/home/tbehrendt/.kube/config"],
"envFile": ".env"
}
]
}
+2 -2
View File
@@ -1,4 +1,4 @@
FROM docker.io/library/golang:1.25-alpine@sha256:04d017a27c481185c169884328a5761d052910fdced8c3b8edd686474efdf59b AS build FROM docker.io/library/golang:1.26.3@sha256:313faae491b410a35402c05d35e7518ae99103d957308e940e1ae2cfa0aac29b AS build
ARG GOARCH=amd64 ARG GOARCH=amd64
@@ -9,6 +9,6 @@ COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} \ RUN CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} \
go build -trimpath -ldflags="-s -w" -o main . go build -trimpath -ldflags="-s -w" -o main .
FROM gcr.io/distroless/static-debian12@sha256:20bc6c0bc4d625a22a8fde3e55f6515709b32055ef8fb9cfbddaa06d1760f838 FROM gcr.io/distroless/static-debian12@sha256:9c346e4be81b5ca7ff31a0d89eaeade58b0f95cfd3baed1f36083ddb47ca3160
COPY --from=build /app/main / COPY --from=build /app/main /
CMD ["/main"] CMD ["/main"]
+34 -3
View File
@@ -1,9 +1,40 @@
ifneq (,$(wildcard ./.env))
include .env
export
endif
.PHONY: build run codegen build-image test test-unit test-coverage lint format check-format
build: build:
go build go build -o main
build-image:
docker build -t authentik-kubernetes-operator:latest .
run: run:
make build make build
./main ./main --kubeconfig=/home/tbehrendt/.kube/config
codegen: codegen:
./hack/update-codegen.sh ./scripts/codegen.sh
test: test-unit test-coverage
test-unit:
go test ./... -coverprofile=coverage.out
test-coverage:
go tool gcov2lcov -infile coverage.out > lcov.info
lint:
go vet ./...
format:
gofmt -w .
check-format:
@OUTPUT=$$(gofmt -l .); \
if [ -n "$$OUTPUT" ]; then \
echo "Formatter failed for:"; \
echo "$$OUTPUT"; \
exit 1; \
fi
+95 -1
View File
@@ -2,4 +2,98 @@
Authentik Kubernetes Operator allows to manage Authentik resources directly in Kubernetes using Custom Kubernetes Resources. Authentik Kubernetes Operator allows to manage Authentik resources directly in Kubernetes using Custom Kubernetes Resources.
## Features The custom resources of this operator ultimately will mirror the Authentik resources. New resources will be added as there is a need for them.
Manual changes to the resources in Authentik will be overwritten by the operator. So always manage the resources in Kubernetes.
## Custom Resources
| Custom Resource | CRD File | Short Name |
| --------------- | ---------------------------------------------------------- | ---------- |
| ProxyProvider | [`proxyProvider.yaml`](`artifacts/crd/proxyProvider.yaml`) | pp |
| Application | [`application.yaml`](`artifacts/crd/application.yaml`) | app |
| PolicyBinding | [`policyBinding.yaml`](`artifacts/crd/policyBinding.yaml`) | pb |
### ProxyProvider
Currently only the "Forward Single" ProxyProvider is supported and only a reduced set of fields are exposed by the custom resources.
Example [`proxyProvider.yaml`](`artifacts/examples/proxyProvider.yaml`):
```yaml
apiVersion: proxyprovider.t000-n.de/v1alpha1
kind: ProxyProvider
metadata:
name: proxy-provider-example
namespace: kube-system
spec:
name: proxy-provider-example
# The ID of the authorization flow. In this example: "default-provider-authorization-implicit-consent (Authorize Application)"
authorization_flow: 16896c6d-b326-42d1-8d3f-93f32921962e
# The ID of the invalidation flow. In this example: "default-provider-invalidation-flow (Logged out of application)"
invalidation_flow: 7acac1ef-19e3-4a6f-8d8d-14ca7031d184
# The external host of your application.
external_host: https://example.t00n.de
# The ID of the outpost, which at current point in time can only be retrieved from Authentik directly. In this example: "Proxy-Forward-Auth-Auto"
outpost: e004ffe7-4af6-4ac1-9e9d-522354799e1f
```
The ProxyProvider will be created in Authentik and assigned to the configured outpost.
### Application
The Application only supports a reduced set of fields.
Example [`application.yaml`](`artifacts/examples/application.yaml`):
```yaml
apiVersion: application.t000-n.de/v1alpha1
kind: Application
metadata:
name: application-example
spec:
name: Application Example
slug: application-example
# The ID of the provider, which can be retrieved from e.g. the ProxyPRovider via "kubectl get pp proxy-provider-example -o jsonpath='{.status.pk}'"
provider: 105
```
### PolicyBinding
The PolicyBinding is used to bind a policy to a target, e.g. allow a group or user to access an application.
The PolicyBinding only supports a reduced set of fields.
Example [`policyBinding.yaml`](`artifacts/examples/policyBinding.yaml`):
```yaml
apiVersion: policybinding.t000-n.de/v1alpha1
kind: PolicyBinding
metadata:
name: policy-binding-example
spec:
group: 14ab813f-a7f9-481b-9b08-781953ae9ebf
# The ID of the target, e.g. an Application, which can be retrieved from e.g. the Application via "kubectl get app application-example -o jsonpath='{.status.pk}'"
target: 8dd85627-9c48-49c2-8afc-d73dd122ffc2
# The order in which the policy is applied. This needs to be unique for each PolicyBinding.
order: 1
```
## Versioning
As soon as the operator covers an entire use case, the version will be raised to v1 and follow default versioning rules. Before that, the version will be v1alpha1.
## Development
### Guidelines & Tips
- Only do a single reconciliation at a time and then return.
- This is because your references from the k8s API get stale after each update.
- Whenever you update a resource, k8s API will send a new event to your controller, which will trigger a new reconciliation.
- The API will periodically send a resource to the controller for re-syncing, giving the controller a chance to reconcile the state with the outside world.
- Use finalizers to ensure that the controller gets a chance to reconcile the state with the outside world before the object is deleted. If no finalizer is present, the object is deleted immediately without the controller seeing it.
- Use the resource's state to keep track of the current state of the outside world, e.g. identifiers of external resources, etc.
### References
- [Extend Kubernetes](https://kubernetes.io/docs/concepts/extend-kubernetes/#api-extensions)
- [Example Controller Implementation](https://github.com/kubernetes/sample-controller)
+56
View File
@@ -0,0 +1,56 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: applications.application.t000-n.de
spec:
group: application.t000-n.de
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
additionalPrinterColumns:
- name: PK
type: string
jsonPath: .status.pk
- name: Name
type: string
jsonPath: .spec.name
- name: Slug
type: string
jsonPath: .spec.slug
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
name:
type: string
description: Application's display name
slug:
type: string
description: Internal application name, used in URLs.
pattern: ^[-a-zA-Z0-9_]+$
provider:
type: integer
format: int32
required:
- name
- slug
status:
type: object
properties:
pk:
type: string
format: uuid
required:
- pk
names:
kind: Application
plural: applications
shortNames:
- app
scope: Namespaced
+53
View File
@@ -0,0 +1,53 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: policybindings.policybinding.t000-n.de
spec:
group: policybinding.t000-n.de
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
additionalPrinterColumns:
- name: PK
type: string
jsonPath: .status.pk
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
policy:
type: string
format: uuid
group:
type: string
format: uuid
user:
type: integer
format: int32
target:
type: string
format: uuid
order:
type: integer
required:
- target
- order
status:
type: object
properties:
pk:
type: string
required:
- pk
names:
kind: PolicyBinding
plural: policybindings
shortNames:
- pb
scope: Namespaced
+58
View File
@@ -0,0 +1,58 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: proxyproviders.proxyprovider.t000-n.de
finalizers:
- proxyprovider.t000-n.de/delete-authentik-proxyprovider
spec:
group: proxyprovider.t000-n.de
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
additionalPrinterColumns:
- name: PK
type: string
jsonPath: .status.pk
- name: Outpost
type: string
jsonPath: .spec.outpost
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
name:
type: string
authorization_flow:
type: string
invalidation_flow:
type: string
external_host:
type: string
outpost:
type: string
format: uuid
required:
- name
- authorization_flow
- invalidation_flow
- external_host
- outpost
status:
type: object
properties:
pk:
type: string
required:
- pk
names:
kind: ProxyProvider
plural: proxyproviders
shortNames:
- pp
scope: Namespaced
+8
View File
@@ -0,0 +1,8 @@
apiVersion: application.t000-n.de/v1alpha1
kind: Application
metadata:
name: application-example
spec:
name: Application Example
slug: application-example
provider: 105
@@ -1,41 +0,0 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: foos.samplecontroller.k8s.io
# for more information on the below annotation, please see
# https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/2337-k8s.io-group-protection/README.md
annotations:
"api-approved.kubernetes.io": "unapproved, experimental-only; please get an approval from Kubernetes API reviewers if you're trying to develop a CRD in the *.k8s.io or *.kubernetes.io groups"
spec:
group: samplecontroller.k8s.io
versions:
- name: v1alpha1
served: true
storage: true
schema:
# schema used for validation
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
deploymentName:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
status:
type: object
properties:
availableReplicas:
type: integer
# subresources for the custom resource
subresources:
# enables the status subresource
status: {}
names:
kind: Foo
plural: foos
scope: Namespaced
-37
View File
@@ -1,37 +0,0 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: foos.samplecontroller.k8s.io
# for more information on the below annotation, please see
# https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/2337-k8s.io-group-protection/README.md
annotations:
"api-approved.kubernetes.io": "unapproved, experimental-only; please get an approval from Kubernetes API reviewers if you're trying to develop a CRD in the *.k8s.io or *.kubernetes.io groups"
spec:
group: samplecontroller.k8s.io
versions:
- name: v1alpha1
served: true
storage: true
schema:
# schema used for validation
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
deploymentName:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
status:
type: object
properties:
availableReplicas:
type: integer
names:
kind: Foo
plural: foos
scope: Namespaced
-7
View File
@@ -1,7 +0,0 @@
apiVersion: samplecontroller.k8s.io/v1alpha1
kind: Foo
metadata:
name: example-foo
spec:
deploymentName: example-foo
replicas: 1
+8
View File
@@ -0,0 +1,8 @@
apiVersion: policybinding.t000-n.de/v1alpha1
kind: PolicyBinding
metadata:
name: policy-binding-example
spec:
group: 14ab813f-a7f9-481b-9b08-781953ae9ebf
target: 8dd85627-9c48-49c2-8afc-d73dd122ffc2
order: 1
+12
View File
@@ -0,0 +1,12 @@
# Example ProxyProvider CRD
apiVersion: proxyprovider.t000-n.de/v1alpha1
kind: ProxyProvider
metadata:
name: proxy-provider-example
namespace: kube-system
spec:
name: proxy-provider-example
authorization_flow: 16896c6d-b326-42d1-8d3f-93f32921962e
invalidation_flow: 7acac1ef-19e3-4a6f-8d8d-14ca7031d184
external_host: https://example.t00n.de
outpost: ce8f74c0-88cd-47fe-96f5-d6507b739ceb
-421
View File
@@ -1,421 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"time"
"golang.org/x/time/rate"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
appsinformers "k8s.io/client-go/informers/apps/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
appslisters "k8s.io/client-go/listers/apps/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
samplev1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
samplescheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/samplecontroller/v1alpha1"
listers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/samplecontroller/v1alpha1"
)
const controllerAgentName = "sample-controller"
const (
// SuccessSynced is used as part of the Event 'reason' when a Foo is synced
SuccessSynced = "Synced"
// ErrResourceExists is used as part of the Event 'reason' when a Foo fails
// to sync due to a Deployment of the same name already existing.
ErrResourceExists = "ErrResourceExists"
// MessageResourceExists is the message used for Events when a resource
// fails to sync due to a Deployment already existing
MessageResourceExists = "Resource %q already exists and is not managed by Foo"
// MessageResourceSynced is the message used for an Event fired when a Foo
// is synced successfully
MessageResourceSynced = "Foo synced successfully"
// FieldManager distinguishes this controller from other things writing to API objects
FieldManager = controllerAgentName
)
// Controller is the controller implementation for Foo resources
type Controller struct {
// kubeclientset is a standard kubernetes clientset
kubeclientset kubernetes.Interface
// sampleclientset is a clientset for our own API group
sampleclientset clientset.Interface
deploymentsLister appslisters.DeploymentLister
deploymentsSynced cache.InformerSynced
foosLister listers.FooLister
foosSynced cache.InformerSynced
// workqueue is a rate limited work queue. This is used to queue work to be
// processed instead of performing it as soon as a change happens. This
// means we can ensure we only process a fixed amount of resources at a
// time, and makes it easy to ensure we are never processing the same item
// simultaneously in two different workers.
workqueue workqueue.TypedRateLimitingInterface[cache.ObjectName]
// recorder is an event recorder for recording Event resources to the
// Kubernetes API.
recorder record.EventRecorder
}
// NewController returns a new sample controller
func NewController(
ctx context.Context,
kubeclientset kubernetes.Interface,
sampleclientset clientset.Interface,
deploymentInformer appsinformers.DeploymentInformer,
fooInformer informers.FooInformer) *Controller {
logger := klog.FromContext(ctx)
// Create event broadcaster
// Add sample-controller types to the default Kubernetes Scheme so Events can be
// logged for sample-controller types.
utilruntime.Must(samplescheme.AddToScheme(scheme.Scheme))
logger.V(4).Info("Creating event broadcaster")
eventBroadcaster := record.NewBroadcaster(record.WithContext(ctx))
eventBroadcaster.StartStructuredLogging(0)
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
ratelimiter := workqueue.NewTypedMaxOfRateLimiter(
workqueue.NewTypedItemExponentialFailureRateLimiter[cache.ObjectName](5*time.Millisecond, 1000*time.Second),
&workqueue.TypedBucketRateLimiter[cache.ObjectName]{Limiter: rate.NewLimiter(rate.Limit(50), 300)},
)
controller := &Controller{
kubeclientset: kubeclientset,
sampleclientset: sampleclientset,
deploymentsLister: deploymentInformer.Lister(),
deploymentsSynced: deploymentInformer.Informer().HasSynced,
foosLister: fooInformer.Lister(),
foosSynced: fooInformer.Informer().HasSynced,
workqueue: workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder: recorder,
}
logger.Info("Setting up event handlers")
// Set up an event handler for when Foo resources change
fooInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: controller.enqueueFoo,
UpdateFunc: func(old, new interface{}) {
controller.enqueueFoo(new)
},
})
// Set up an event handler for when Deployment resources change. This
// handler will lookup the owner of the given Deployment, and if it is
// owned by a Foo resource then the handler will enqueue that Foo resource for
// processing. This way, we don't need to implement custom logic for
// handling Deployment resources. More info on this pattern:
// https://github.com/kubernetes/community/blob/8cafef897a22026d42f5e5bb3f104febe7e29830/contributors/devel/controllers.md
deploymentInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: controller.handleObject,
UpdateFunc: func(old, new interface{}) {
newDepl := new.(*appsv1.Deployment)
oldDepl := old.(*appsv1.Deployment)
if newDepl.ResourceVersion == oldDepl.ResourceVersion {
// Periodic resync will send update events for all known Deployments.
// Two different versions of the same Deployment will always have different RVs.
return
}
controller.handleObject(new)
},
DeleteFunc: controller.handleObject,
})
return controller
}
// Run will set up the event handlers for types we are interested in, as well
// as syncing informer caches and starting workers. It will block until stopCh
// is closed, at which point it will shutdown the workqueue and wait for
// workers to finish processing their current work items.
func (c *Controller) Run(ctx context.Context, workers int) error {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
logger := klog.FromContext(ctx)
// Start the informer factories to begin populating the informer caches
logger.Info("Starting Foo controller")
// Wait for the caches to be synced before starting workers
logger.Info("Waiting for informer caches to sync")
if ok := cache.WaitForCacheSync(ctx.Done(), c.deploymentsSynced, c.foosSynced); !ok {
return fmt.Errorf("failed to wait for caches to sync")
}
logger.Info("Starting workers", "count", workers)
// Launch two workers to process Foo resources
for i := 0; i < workers; i++ {
go wait.UntilWithContext(ctx, c.runWorker, time.Second)
}
logger.Info("Started workers")
<-ctx.Done()
logger.Info("Shutting down workers")
return nil
}
// runWorker is a long-running function that will continually call the
// processNextWorkItem function in order to read and process a message on the
// workqueue.
func (c *Controller) runWorker(ctx context.Context) {
for c.processNextWorkItem(ctx) {
}
}
// processNextWorkItem will read a single work item off the workqueue and
// attempt to process it, by calling the syncHandler.
func (c *Controller) processNextWorkItem(ctx context.Context) bool {
objRef, shutdown := c.workqueue.Get()
logger := klog.FromContext(ctx)
if shutdown {
return false
}
// We call Done at the end of this func so the workqueue knows we have
// finished processing this item. We also must remember to call Forget
// if we do not want this work item being re-queued. For example, we do
// not call Forget if a transient error occurs, instead the item is
// put back on the workqueue and attempted again after a back-off
// period.
defer c.workqueue.Done(objRef)
// Run the syncHandler, passing it the structured reference to the object to be synced.
err := c.syncHandler(ctx, objRef)
if err == nil {
// If no error occurs then we Forget this item so it does not
// get queued again until another change happens.
c.workqueue.Forget(objRef)
logger.Info("Successfully synced", "objectName", objRef)
return true
}
// there was a failure so be sure to report it. This method allows for
// pluggable error handling which can be used for things like
// cluster-monitoring.
utilruntime.HandleErrorWithContext(ctx, err, "Error syncing; requeuing for later retry", "objectReference", objRef)
// since we failed, we should requeue the item to work on later. This
// method will add a backoff to avoid hotlooping on particular items
// (they're probably still not going to work right away) and overall
// controller protection (everything I've done is broken, this controller
// needs to calm down or it can starve other useful work) cases.
c.workqueue.AddRateLimited(objRef)
return true
}
// syncHandler compares the actual state with the desired, and attempts to
// converge the two. It then updates the Status block of the Foo resource
// with the current status of the resource.
func (c *Controller) syncHandler(ctx context.Context, objectRef cache.ObjectName) error {
logger := klog.LoggerWithValues(klog.FromContext(ctx), "objectRef", objectRef)
// Get the Foo resource with this namespace/name
foo, err := c.foosLister.Foos(objectRef.Namespace).Get(objectRef.Name)
if err != nil {
// The Foo resource may no longer exist, in which case we stop
// processing.
if errors.IsNotFound(err) {
utilruntime.HandleErrorWithContext(ctx, err, "Foo referenced by item in work queue no longer exists", "objectReference", objectRef)
return nil
}
return err
}
deploymentName := foo.Spec.DeploymentName
if deploymentName == "" {
// We choose to absorb the error here as the worker would requeue the
// resource otherwise. Instead, the next time the resource is updated
// the resource will be queued again.
utilruntime.HandleErrorWithContext(ctx, nil, "Deployment name missing from object reference", "objectReference", objectRef)
return nil
}
// Get the deployment with the name specified in Foo.spec
deployment, err := c.deploymentsLister.Deployments(foo.Namespace).Get(deploymentName)
// If the resource doesn't exist, we'll create it
if errors.IsNotFound(err) {
deployment, err = c.kubeclientset.AppsV1().Deployments(foo.Namespace).Create(ctx, newDeployment(foo), metav1.CreateOptions{FieldManager: FieldManager})
}
// If an error occurs during Get/Create, we'll requeue the item so we can
// attempt processing again later. This could have been caused by a
// temporary network failure, or any other transient reason.
if err != nil {
return err
}
// If the Deployment is not controlled by this Foo resource, we should log
// a warning to the event recorder and return error msg.
if !metav1.IsControlledBy(deployment, foo) {
msg := fmt.Sprintf(MessageResourceExists, deployment.Name)
c.recorder.Event(foo, corev1.EventTypeWarning, ErrResourceExists, msg)
return fmt.Errorf("%s", msg)
}
// If this number of the replicas on the Foo resource is specified, and the
// number does not equal the current desired replicas on the Deployment, we
// should update the Deployment resource.
if foo.Spec.Replicas != nil && *foo.Spec.Replicas != *deployment.Spec.Replicas {
logger.V(4).Info("Update deployment resource", "currentReplicas", *deployment.Spec.Replicas, "desiredReplicas", *foo.Spec.Replicas)
deployment, err = c.kubeclientset.AppsV1().Deployments(foo.Namespace).Update(ctx, newDeployment(foo), metav1.UpdateOptions{FieldManager: FieldManager})
}
// If an error occurs during Update, we'll requeue the item so we can
// attempt processing again later. This could have been caused by a
// temporary network failure, or any other transient reason.
if err != nil {
return err
}
// Finally, we update the status block of the Foo resource to reflect the
// current state of the world
err = c.updateFooStatus(ctx, foo, deployment)
if err != nil {
return err
}
c.recorder.Event(foo, corev1.EventTypeNormal, SuccessSynced, MessageResourceSynced)
return nil
}
func (c *Controller) updateFooStatus(ctx context.Context, foo *samplev1alpha1.Foo, deployment *appsv1.Deployment) error {
// NEVER modify objects from the store. It's a read-only, local cache.
// You can use DeepCopy() to make a deep copy of original object and modify this copy
// Or create a copy manually for better performance
fooCopy := foo.DeepCopy()
fooCopy.Status.AvailableReplicas = deployment.Status.AvailableReplicas
// If the CustomResourceSubresources feature gate is not enabled,
// we must use Update instead of UpdateStatus to update the Status block of the Foo resource.
// UpdateStatus will not allow changes to the Spec of the resource,
// which is ideal for ensuring nothing other than resource status has been updated.
_, err := c.sampleclientset.SamplecontrollerV1alpha1().Foos(foo.Namespace).UpdateStatus(ctx, fooCopy, metav1.UpdateOptions{FieldManager: FieldManager})
return err
}
// enqueueFoo takes a Foo resource and converts it into a namespace/name
// string which is then put onto the work queue. This method should *not* be
// passed resources of any type other than Foo.
func (c *Controller) enqueueFoo(obj interface{}) {
if objectRef, err := cache.ObjectToName(obj); err != nil {
utilruntime.HandleError(err)
return
} else {
c.workqueue.Add(objectRef)
}
}
// handleObject will take any resource implementing metav1.Object and attempt
// to find the Foo resource that 'owns' it. It does this by looking at the
// objects metadata.ownerReferences field for an appropriate OwnerReference.
// It then enqueues that Foo resource to be processed. If the object does not
// have an appropriate OwnerReference, it will simply be skipped.
func (c *Controller) handleObject(obj interface{}) {
var object metav1.Object
var ok bool
logger := klog.FromContext(context.Background())
if object, ok = obj.(metav1.Object); !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
// If the object value is not too big and does not contain sensitive information then
// it may be useful to include it.
utilruntime.HandleErrorWithContext(context.Background(), nil, "Error decoding object, invalid type", "type", fmt.Sprintf("%T", obj))
return
}
object, ok = tombstone.Obj.(metav1.Object)
if !ok {
// If the object value is not too big and does not contain sensitive information then
// it may be useful to include it.
utilruntime.HandleErrorWithContext(context.Background(), nil, "Error decoding object tombstone, invalid type", "type", fmt.Sprintf("%T", tombstone.Obj))
return
}
logger.V(4).Info("Recovered deleted object", "resourceName", object.GetName())
}
logger.V(4).Info("Processing object", "object", klog.KObj(object))
if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
// If this object is not owned by a Foo, we should not do anything more
// with it.
if ownerRef.Kind != "Foo" {
return
}
foo, err := c.foosLister.Foos(object.GetNamespace()).Get(ownerRef.Name)
if err != nil {
logger.V(4).Info("Ignore orphaned object", "object", klog.KObj(object), "foo", ownerRef.Name)
return
}
c.enqueueFoo(foo)
return
}
}
// newDeployment creates a new Deployment for a Foo resource. It also sets
// the appropriate OwnerReferences on the resource so handleObject can discover
// the Foo resource that 'owns' it.
func newDeployment(foo *samplev1alpha1.Foo) *appsv1.Deployment {
labels := map[string]string{
"app": "nginx",
"controller": foo.Name,
}
return &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: foo.Spec.DeploymentName,
Namespace: foo.Namespace,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(foo, samplev1alpha1.SchemeGroupVersion.WithKind("Foo")),
},
},
Spec: appsv1.DeploymentSpec{
Replicas: foo.Spec.Replicas,
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:latest",
},
},
},
},
},
}
}
-316
View File
@@ -1,316 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"reflect"
"testing"
"time"
apps "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
kubeinformers "k8s.io/client-go/informers"
k8sfake "k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2/ktesting"
"k8s.io/utils/ptr"
samplecontroller "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/fake"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions"
)
var (
alwaysReady = func() bool { return true }
noResyncPeriodFunc = func() time.Duration { return 0 }
)
type fixture struct {
t *testing.T
client *fake.Clientset
kubeclient *k8sfake.Clientset
// Objects to put in the store.
fooLister []*samplecontroller.Foo
deploymentLister []*apps.Deployment
// Actions expected to happen on the client.
kubeactions []core.Action
actions []core.Action
// Objects from here preloaded into NewSimpleFake.
kubeobjects []runtime.Object
objects []runtime.Object
}
func newFixture(t *testing.T) *fixture {
f := &fixture{}
f.t = t
f.objects = []runtime.Object{}
f.kubeobjects = []runtime.Object{}
return f
}
func newFoo(name string, replicas *int32) *samplecontroller.Foo {
return &samplecontroller.Foo{
TypeMeta: metav1.TypeMeta{APIVersion: samplecontroller.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: metav1.NamespaceDefault,
},
Spec: samplecontroller.FooSpec{
DeploymentName: fmt.Sprintf("%s-deployment", name),
Replicas: replicas,
},
}
}
func (f *fixture) newController(ctx context.Context) (*Controller, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) {
f.client = fake.NewClientset(f.objects...)
f.kubeclient = k8sfake.NewClientset(f.kubeobjects...)
i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc())
k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc())
c := NewController(ctx, f.kubeclient, f.client,
k8sI.Apps().V1().Deployments(), i.Samplecontroller().V1alpha1().Foos())
c.foosSynced = alwaysReady
c.deploymentsSynced = alwaysReady
c.recorder = &record.FakeRecorder{}
for _, f := range f.fooLister {
i.Samplecontroller().V1alpha1().Foos().Informer().GetIndexer().Add(f)
}
for _, d := range f.deploymentLister {
k8sI.Apps().V1().Deployments().Informer().GetIndexer().Add(d)
}
return c, i, k8sI
}
func (f *fixture) run(ctx context.Context, fooRef cache.ObjectName) {
f.runController(ctx, fooRef, true, false)
}
func (f *fixture) runExpectError(ctx context.Context, fooRef cache.ObjectName) {
f.runController(ctx, fooRef, true, true)
}
func (f *fixture) runController(ctx context.Context, fooRef cache.ObjectName, startInformers bool, expectError bool) {
c, i, k8sI := f.newController(ctx)
if startInformers {
i.Start(ctx.Done())
k8sI.Start(ctx.Done())
}
err := c.syncHandler(ctx, fooRef)
if !expectError && err != nil {
f.t.Errorf("error syncing foo: %v", err)
} else if expectError && err == nil {
f.t.Error("expected error syncing foo, got nil")
}
actions := filterInformerActions(f.client.Actions())
for i, action := range actions {
if len(f.actions) < i+1 {
f.t.Errorf("%d unexpected actions: %+v", len(actions)-len(f.actions), actions[i:])
break
}
expectedAction := f.actions[i]
checkAction(expectedAction, action, f.t)
}
if len(f.actions) > len(actions) {
f.t.Errorf("%d additional expected actions:%+v", len(f.actions)-len(actions), f.actions[len(actions):])
}
k8sActions := filterInformerActions(f.kubeclient.Actions())
for i, action := range k8sActions {
if len(f.kubeactions) < i+1 {
f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeactions), k8sActions[i:])
break
}
expectedAction := f.kubeactions[i]
checkAction(expectedAction, action, f.t)
}
if len(f.kubeactions) > len(k8sActions) {
f.t.Errorf("%d additional expected actions:%+v", len(f.kubeactions)-len(k8sActions), f.kubeactions[len(k8sActions):])
}
}
// checkAction verifies that expected and actual actions are equal and both have
// same attached resources
func checkAction(expected, actual core.Action, t *testing.T) {
if !(expected.Matches(actual.GetVerb(), actual.GetResource().Resource) && actual.GetSubresource() == expected.GetSubresource()) {
t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expected, actual)
return
}
if reflect.TypeOf(actual) != reflect.TypeOf(expected) {
t.Errorf("Action has wrong type. Expected: %t. Got: %t", expected, actual)
return
}
switch a := actual.(type) {
case core.CreateActionImpl:
e, _ := expected.(core.CreateActionImpl)
expObject := e.GetObject()
object := a.GetObject()
if !reflect.DeepEqual(expObject, object) {
t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object))
}
case core.UpdateActionImpl:
e, _ := expected.(core.UpdateActionImpl)
expObject := e.GetObject()
object := a.GetObject()
if !reflect.DeepEqual(expObject, object) {
t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object))
}
case core.PatchActionImpl:
e, _ := expected.(core.PatchActionImpl)
expPatch := e.GetPatch()
patch := a.GetPatch()
if !reflect.DeepEqual(expPatch, patch) {
t.Errorf("Action %s %s has wrong patch\nDiff:\n %s",
a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expPatch, patch))
}
default:
t.Errorf("Uncaptured Action %s %s, you should explicitly add a case to capture it",
actual.GetVerb(), actual.GetResource().Resource)
}
}
// filterInformerActions filters list and watch actions for testing resources.
// Since list and watch don't change resource state we can filter it to lower
// nose level in our tests.
func filterInformerActions(actions []core.Action) []core.Action {
ret := []core.Action{}
for _, action := range actions {
if len(action.GetNamespace()) == 0 &&
(action.Matches("list", "foos") ||
action.Matches("watch", "foos") ||
action.Matches("list", "deployments") ||
action.Matches("watch", "deployments")) {
continue
}
ret = append(ret, action)
}
return ret
}
func (f *fixture) expectCreateDeploymentAction(d *apps.Deployment) {
f.kubeactions = append(f.kubeactions, core.NewCreateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
}
func (f *fixture) expectUpdateDeploymentAction(d *apps.Deployment) {
f.kubeactions = append(f.kubeactions, core.NewUpdateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
}
func (f *fixture) expectUpdateFooStatusAction(foo *samplecontroller.Foo) {
action := core.NewUpdateSubresourceAction(schema.GroupVersionResource{Resource: "foos"}, "status", foo.Namespace, foo)
f.actions = append(f.actions, action)
}
func getRef(foo *samplecontroller.Foo, t *testing.T) cache.ObjectName {
ref := cache.MetaObjectToName(foo)
return ref
}
func TestCreatesDeployment(t *testing.T) {
f := newFixture(t)
foo := newFoo("test", ptr.To[int32](1))
_, ctx := ktesting.NewTestContext(t)
f.fooLister = append(f.fooLister, foo)
f.objects = append(f.objects, foo)
expDeployment := newDeployment(foo)
f.expectCreateDeploymentAction(expDeployment)
f.expectUpdateFooStatusAction(foo)
f.run(ctx, getRef(foo, t))
}
func TestDoNothing(t *testing.T) {
f := newFixture(t)
foo := newFoo("test", ptr.To[int32](1))
_, ctx := ktesting.NewTestContext(t)
d := newDeployment(foo)
f.fooLister = append(f.fooLister, foo)
f.objects = append(f.objects, foo)
f.deploymentLister = append(f.deploymentLister, d)
f.kubeobjects = append(f.kubeobjects, d)
f.expectUpdateFooStatusAction(foo)
f.run(ctx, getRef(foo, t))
}
func TestUpdateDeployment(t *testing.T) {
f := newFixture(t)
foo := newFoo("test", ptr.To[int32](1))
_, ctx := ktesting.NewTestContext(t)
d := newDeployment(foo)
// Update replicas
foo.Spec.Replicas = ptr.To[int32](2)
expDeployment := newDeployment(foo)
f.fooLister = append(f.fooLister, foo)
f.objects = append(f.objects, foo)
f.deploymentLister = append(f.deploymentLister, d)
f.kubeobjects = append(f.kubeobjects, d)
f.expectUpdateFooStatusAction(foo)
f.expectUpdateDeploymentAction(expDeployment)
f.run(ctx, getRef(foo, t))
}
func TestNotControlledByUs(t *testing.T) {
f := newFixture(t)
foo := newFoo("test", ptr.To[int32](1))
_, ctx := ktesting.NewTestContext(t)
d := newDeployment(foo)
d.ObjectMeta.OwnerReferences = []metav1.OwnerReference{}
f.fooLister = append(f.fooLister, foo)
f.objects = append(f.objects, foo)
f.deploymentLister = append(f.deploymentLister, d)
f.kubeobjects = append(f.kubeobjects, d)
f.runExpectError(ctx, getRef(foo, t))
}
+12 -11
View File
@@ -5,15 +5,14 @@ go 1.26.3
godebug default=go1.26 godebug default=go1.26
require ( require (
goauthentik.io/api/v3 v3.2026020.16
golang.org/x/time v0.15.0 golang.org/x/time v0.15.0
k8s.io/api v0.0.0-20260509204538-0dfb117cc6ec k8s.io/api v0.36.0
k8s.io/apimachinery v0.0.0-20260509204146-64dfe1db2af5 k8s.io/apimachinery v0.36.0
k8s.io/client-go v0.0.0-20260509205101-ca52b81a2940 k8s.io/client-go v0.36.0
k8s.io/code-generator v0.0.0-20260509210052-5595d1310975
k8s.io/klog/v2 v2.140.0 k8s.io/klog/v2 v2.140.0
k8s.io/kube-openapi v0.0.0-20260509150519-312035bf509b k8s.io/kube-openapi v0.0.0-20260511211612-da4e56fe5676
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 sigs.k8s.io/structured-merge-diff/v6 v6.4.0
sigs.k8s.io/structured-merge-diff/v6 v6.3.2
) )
require ( require (
@@ -37,6 +36,7 @@ require (
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/google/gnostic-models v0.7.0 // indirect github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/jandelgado/gcov2lcov v1.1.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
@@ -46,19 +46,20 @@ require (
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.35.0 // indirect
golang.org/x/net v0.53.0 // indirect golang.org/x/net v0.53.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.43.0 // indirect golang.org/x/sys v0.43.0 // indirect
golang.org/x/term v0.42.0 // indirect golang.org/x/term v0.42.0 // indirect
golang.org/x/text v0.36.0 // indirect golang.org/x/text v0.36.0 // indirect
golang.org/x/tools v0.44.0 // indirect
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect
) )
replace k8s.io/code-generator => ./code-generator
tool github.com/jandelgado/gcov2lcov
+24 -20
View File
@@ -49,6 +49,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jandelgado/gcov2lcov v1.1.1 h1:CHUNoAglvb34DqmMoZchnzDbA3yjpzT8EoUvVqcAY+s=
github.com/jandelgado/gcov2lcov v1.1.1/go.mod h1:tMVUlMVtS1po2SB8UkADWhOT5Y5Q13XOce2AYU69JuI=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -71,9 +73,16 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
@@ -84,14 +93,12 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= goauthentik.io/api/v3 v3.2026020.16 h1:sEqcVRXYSJTYaSdU5PzSEdFUWDqCONm5BeL62F5k+58=
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= goauthentik.io/api/v3 v3.2026020.16/go.mod h1:82lqAz4jxzl6Cg0YDbhNtvvTG2rm6605ZhdJFnbbsl8=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
@@ -100,12 +107,6 @@ golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -115,29 +116,32 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnf
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.0.0-20260509204538-0dfb117cc6ec h1:xf12Yh3ltN4fnNyP0CyyM0TwNVnZDfLJjV3+bf9fPFY= k8s.io/api v0.0.0-20260509204538-0dfb117cc6ec h1:xf12Yh3ltN4fnNyP0CyyM0TwNVnZDfLJjV3+bf9fPFY=
k8s.io/api v0.0.0-20260509204538-0dfb117cc6ec/go.mod h1:C+fcNlNQ9TcKHspN+DD7UybdfnjDAGyBjfCd6W7ogbY= k8s.io/api v0.0.0-20260509204538-0dfb117cc6ec/go.mod h1:C+fcNlNQ9TcKHspN+DD7UybdfnjDAGyBjfCd6W7ogbY=
k8s.io/apimachinery v0.0.0-20260509204146-64dfe1db2af5 h1:k2HBxRBq6w2QCj14oAhBosjMqqgNlj4dmLXFj8f1A+8= k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80=
k8s.io/apimachinery v0.0.0-20260509204146-64dfe1db2af5/go.mod h1:37ALVDWo0LgW74Y9rAdewmZo20SVCGGH34806wUMrko= k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34=
k8s.io/apimachinery v0.0.0-20260513183604-f9371b815e42 h1:rWdGOTor3z0WSyZcRl9ms4dn9Cw9CqmNBqXuf2z0k1k=
k8s.io/apimachinery v0.0.0-20260513183604-f9371b815e42/go.mod h1:hiubQ6UTHIdr0bS8ExXOJEywFVOoudnldm/l/NiNVlA=
k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ=
k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc=
k8s.io/client-go v0.0.0-20260509205101-ca52b81a2940 h1:n5t5Jx3VpLdiAGxIvIHsZDmsExtZVwghUPLM3wFi6Go= k8s.io/client-go v0.0.0-20260509205101-ca52b81a2940 h1:n5t5Jx3VpLdiAGxIvIHsZDmsExtZVwghUPLM3wFi6Go=
k8s.io/client-go v0.0.0-20260509205101-ca52b81a2940/go.mod h1:0e7OLwg7kdXISVFwn7ishFdvxfVgi7wsqHqsQPHl61w= k8s.io/client-go v0.0.0-20260509205101-ca52b81a2940/go.mod h1:0e7OLwg7kdXISVFwn7ishFdvxfVgi7wsqHqsQPHl61w=
k8s.io/code-generator v0.0.0-20260509210052-5595d1310975 h1:hDrusFgTzvqcDJ7p13A9Eid4i8Y9uNSs/67lniaYHwM= k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c=
k8s.io/code-generator v0.0.0-20260509210052-5595d1310975/go.mod h1:mQXg0n0EeF4oU8aTwm9mzwoyAKqVRmUb9wLhjHnRq3I= k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y=
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ=
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM=
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
k8s.io/kube-openapi v0.0.0-20260509150519-312035bf509b h1:WrpNVPKkCaOO9h77E1P2HLnhWDQxrxzpf2jfsM8WevY= k8s.io/kube-openapi v0.0.0-20260511211612-da4e56fe5676 h1:ahjrVu/DBcaAhw/GcblfaOvvQ2wi8kqXWvn62nud3UU=
k8s.io/kube-openapi v0.0.0-20260509150519-312035bf509b/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY= k8s.io/kube-openapi v0.0.0-20260511211612-da4e56fe5676/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY=
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo=
sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
@@ -0,0 +1,18 @@
API rule violation: names_match,gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1,ProxyProviderSpec,AuthorizationFlow
API rule violation: names_match,gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1,ProxyProviderSpec,ExternalHost
API rule violation: names_match,gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1,ProxyProviderSpec,InvalidationFlow
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,Format
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,d
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,i
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,s
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,int64Amount,scale
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,int64Amount,value
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,APIResourceList,APIResources
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,Duration,Duration
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,InternalEvent,Object
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,InternalEvent,Type
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,MicroTime,Time
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,StatusCause,Type
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,Time,Time
API rule violation: names_match,k8s.io/apimachinery/pkg/runtime,Unknown,ContentEncoding
API rule violation: names_match,k8s.io/apimachinery/pkg/runtime,Unknown,ContentType
-59
View File
@@ -1,59 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}
source "${CODEGEN_PKG}/kube_codegen.sh"
THIS_PKG="gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator"
kube::codegen::gen_helpers \
--boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
"${SCRIPT_ROOT}/pkg/apis"
if [[ -n "${API_KNOWN_VIOLATIONS_DIR:-}" ]]; then
report_filename="${API_KNOWN_VIOLATIONS_DIR}/sample_controller_violation_exceptions.list"
if [[ "${UPDATE_API_KNOWN_VIOLATIONS:-}" == "true" ]]; then
update_report="--update-report"
fi
fi
kube::codegen::gen_openapi \
--output-dir "${SCRIPT_ROOT}/pkg/generated/openapi" \
--output-pkg "k8s.io/${THIS_PKG}/pkg/generated/openapi" \
--report-filename "${report_filename:-"/dev/null"}" \
--output-model-name-file "zz_generated.model_name.go" \
${update_report:+"${update_report}"} \
--boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
"${SCRIPT_ROOT}/pkg/apis"
kube::codegen::gen_client \
--with-watch \
--with-applyconfig \
--applyconfig-openapi-schema <(go run gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/openapi/cmd/models-schema) \
--output-dir "${SCRIPT_ROOT}/pkg/generated" \
--output-pkg "${THIS_PKG}/pkg/generated" \
--boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
"${SCRIPT_ROOT}/pkg/apis"
kube::codegen::gen_register \
--boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
"${SCRIPT_ROOT}/pkg/apis"
-57
View File
@@ -1,57 +0,0 @@
#!/usr/bin/env bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
DIFFROOT="${SCRIPT_ROOT}/pkg"
TMP_DIFFROOT="$(mktemp -d -t "$(basename "$0").XXXXXX")/pkg"
cleanup() {
rm -rf "${TMP_DIFFROOT}"
}
trap "cleanup" EXIT SIGINT
cleanup
# Ensure model-schema generator matches the version from
# k8s.io/kubernetes/pkg/generated/openapi/cmd/models-schema/main.go
echo "Ensuring models-schema is up-to-date"
K8S_MODELS_SCHEMA="${SCRIPT_ROOT}/../../../../pkg/generated/openapi/cmd/models-schema/main.go"
SAMPLE_CONTROLLER_MODELS_SCHEMA="${SCRIPT_ROOT}/pkg/generated/openapi/cmd/models-schema/main.go"
# these two files will only differ in the imported lines for generated openapi
if ! diff -I "k8s.io/kubernetes/pkg/generated/openapi" \
-I "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/openapi" \
"${K8S_MODELS_SCHEMA}" "${SAMPLE_CONTROLLER_MODELS_SCHEMA}"; then
echo "${SAMPLE_CONTROLLER_MODELS_SCHEMA} is out of date. Compare changes with ${K8S_MODELS_SCHEMA}"
exit 1
fi
mkdir -p "${TMP_DIFFROOT}"
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
"${SCRIPT_ROOT}/hack/update-codegen.sh"
echo "diffing ${DIFFROOT} against freshly generated codegen"
ret=0
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
if [[ $ret -eq 0 ]]; then
echo "${DIFFROOT} up to date."
else
echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
fi
exit $ret
+94
View File
@@ -0,0 +1,94 @@
package baseController
import (
"context"
"fmt"
"time"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
)
type SyncHandler func(ctx context.Context, objRef cache.ObjectName) error
type Controller struct {
workqueue workqueue.TypedRateLimitingInterface[cache.ObjectName]
recorder record.EventRecorder
synced cache.InformerSynced
syncHandler SyncHandler
}
func NewController(
ctx context.Context,
workqueue workqueue.TypedRateLimitingInterface[cache.ObjectName],
recorder record.EventRecorder,
synced cache.InformerSynced,
syncHandler SyncHandler,
) *Controller {
return &Controller{
workqueue: workqueue,
recorder: recorder,
synced: synced,
syncHandler: syncHandler,
}
}
func (c *Controller) Run(ctx context.Context, workers int) error {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
logger := klog.FromContext(ctx)
logger.Info("Starting PolicyBinding controller")
logger.Info("Waiting for informer caches to sync")
if ok := cache.WaitForCacheSync(ctx.Done(), c.synced); !ok {
return fmt.Errorf("failed to wait for caches to sync")
}
logger.Info("Starting workers", "count", workers)
for i := 0; i < workers; i++ {
go wait.UntilWithContext(ctx, c.runWorker, time.Second)
}
logger.Info("Started workers")
<-ctx.Done()
logger.Info("Shutting down workers")
return nil
}
func (c *Controller) runWorker(ctx context.Context) {
for c.processNextWorkItem(ctx) {
}
}
func (c *Controller) processNextWorkItem(ctx context.Context) bool {
objRef, shutdown := c.workqueue.Get()
logger := klog.FromContext(ctx)
if shutdown {
return false
}
defer c.workqueue.Done(objRef)
err := c.syncHandler(ctx, objRef)
if err == nil {
c.workqueue.Forget(objRef)
logger.Info("Successfully synced", "objectName", objRef)
return true
}
utilruntime.HandleErrorWithContext(ctx, err, "Error syncing; requeuing for later retry", "objectReference", objRef)
c.workqueue.AddRateLimited(objRef)
return true
}
func (c *Controller) Enqueue(obj interface{}) {
objectRef, err := cache.ObjectToName(obj)
if err != nil {
utilruntime.HandleError(err)
return
}
c.workqueue.Add(objectRef)
}
+190
View File
@@ -0,0 +1,190 @@
// AI generated tests and not yet reviewed.
package baseController
import (
"context"
"errors"
"sync/atomic"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
)
func newTestController(t *testing.T, synced cache.InformerSynced, syncHandler SyncHandler) (*Controller, workqueue.TypedRateLimitingInterface[cache.ObjectName]) {
t.Helper()
ratelimiter := workqueue.NewTypedItemExponentialFailureRateLimiter[cache.ObjectName](time.Millisecond, time.Second)
q := workqueue.NewTypedRateLimitingQueue(ratelimiter)
t.Cleanup(q.ShutDown)
if synced == nil {
synced = func() bool { return true }
}
ctrl := NewController(
context.Background(),
q,
record.NewFakeRecorder(10),
synced,
syncHandler,
)
return ctrl, q
}
func TestController_processNextWorkItem_success(t *testing.T) {
objRef := cache.ObjectName{Namespace: "default", Name: "test"}
var syncedRef cache.ObjectName
ctrl, q := newTestController(t, nil, func(_ context.Context, ref cache.ObjectName) error {
syncedRef = ref
return nil
})
q.Add(objRef)
if !ctrl.processNextWorkItem(context.Background()) {
t.Fatal("processNextWorkItem() = false, want true")
}
if syncedRef != objRef {
t.Fatalf("syncHandler object = %+v, want %+v", syncedRef, objRef)
}
if q.Len() != 0 {
t.Fatalf("queue length = %d, want 0 after successful sync", q.Len())
}
if q.NumRequeues(objRef) != 0 {
t.Fatalf("requeues = %d, want 0 after successful sync", q.NumRequeues(objRef))
}
}
func TestController_processNextWorkItem_syncError(t *testing.T) {
objRef := cache.ObjectName{Namespace: "default", Name: "test"}
syncErr := errors.New("sync failed")
ctrl, q := newTestController(t, nil, func(context.Context, cache.ObjectName) error {
return syncErr
})
q.Add(objRef)
if !ctrl.processNextWorkItem(context.Background()) {
t.Fatal("processNextWorkItem() = false, want true")
}
if q.NumRequeues(objRef) != 1 {
t.Fatalf("requeues = %d, want 1 after sync error", q.NumRequeues(objRef))
}
}
func TestController_processNextWorkItem_shutdown(t *testing.T) {
ctrl, q := newTestController(t, nil, func(context.Context, cache.ObjectName) error {
return nil
})
q.ShutDown()
if ctrl.processNextWorkItem(context.Background()) {
t.Fatal("processNextWorkItem() = true, want false on shutdown")
}
}
func TestController_Enqueue(t *testing.T) {
ctrl, q := newTestController(t, nil, func(context.Context, cache.ObjectName) error {
return nil
})
obj := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "test",
},
}
ctrl.Enqueue(obj)
if q.Len() != 1 {
t.Fatalf("queue length = %d, want 1 after Enqueue", q.Len())
}
}
func TestController_Enqueue_invalidObject(t *testing.T) {
ctrl, q := newTestController(t, nil, func(context.Context, cache.ObjectName) error {
return nil
})
ctrl.Enqueue("not-a-kubernetes-object")
if q.Len() != 0 {
t.Fatalf("queue length = %d, want 0 for invalid object", q.Len())
}
}
func TestController_Run_cacheSyncFails(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctrl, _ := newTestController(t, func() bool { return false }, func(context.Context, cache.ObjectName) error {
return nil
})
go func() {
time.Sleep(10 * time.Millisecond)
cancel()
}()
err := ctrl.Run(ctx, 1)
if err == nil {
t.Fatal("Run() error = nil, want cache sync failure")
}
}
func TestController_Run_shutsDownOnCancel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
ctrl, _ := newTestController(t, nil, func(context.Context, cache.ObjectName) error {
return nil
})
errCh := make(chan error, 1)
go func() {
errCh <- ctrl.Run(ctx, 1)
}()
time.Sleep(50 * time.Millisecond)
cancel()
select {
case err := <-errCh:
if err != nil {
t.Fatalf("Run() error = %v, want nil on context cancel", err)
}
case <-time.After(2 * time.Second):
t.Fatal("Run() did not return after context cancellation")
}
}
func TestController_runWorker_processesQueuedItem(t *testing.T) {
objRef := cache.ObjectName{Namespace: "default", Name: "test"}
var calls atomic.Int32
ctrl, q := newTestController(t, nil, func(context.Context, cache.ObjectName) error {
calls.Add(1)
return nil
})
q.Add(objRef)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go ctrl.runWorker(ctx)
deadline := time.Now().Add(2 * time.Second)
for time.Now().Before(deadline) {
if calls.Load() == 1 && q.Len() == 0 {
cancel()
return
}
time.Sleep(5 * time.Millisecond)
}
cancel()
t.Fatalf("runWorker did not process queued item: calls=%d queueLen=%d", calls.Load(), q.Len())
}
+85 -14
View File
@@ -17,11 +17,15 @@ limitations under the License.
package main package main
import ( import (
"errors"
"flag" "flag"
"net/url"
"os"
"sync"
"time" "time"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/signals" "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/signals"
kubeinformers "k8s.io/client-go/informers" authentikapi "goauthentik.io/api/v3"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2" "k8s.io/klog/v2"
@@ -29,6 +33,9 @@ import (
// Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters). // Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
// _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
applicationcontroller "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/controllers/application"
policybindingcontroller "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/controllers/policybinding"
proxyprovidercontroller "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/controllers/proxyprovider"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions" informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions"
) )
@@ -58,31 +65,95 @@ func main() {
klog.FlushAndExit(klog.ExitFlushTimeout, 1) klog.FlushAndExit(klog.ExitFlushTimeout, 1)
} }
exampleClient, err := clientset.NewForConfig(cfg) clientset, err := clientset.NewForConfig(cfg)
if err != nil { if err != nil {
logger.Error(err, "Error building kubernetes clientset") logger.Error(err, "Error building proxy provider clientset")
klog.FlushAndExit(klog.ExitFlushTimeout, 1) klog.FlushAndExit(klog.ExitFlushTimeout, 1)
} }
kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, time.Second*30) authentikClient, err := newAuthentikAPIClient(os.Getenv("AUTENTIK_HOST"), os.Getenv("AUTENTIK_TOKEN"))
exampleInformerFactory := informers.NewSharedInformerFactory(exampleClient, time.Second*30) if err != nil {
logger.Error(err, "Error building Authentik API client")
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}
controller := NewController(ctx, kubeClient, exampleClient, proxyProviderInformerFactory := informers.NewSharedInformerFactory(clientset, time.Second*30)
kubeInformerFactory.Apps().V1().Deployments(),
exampleInformerFactory.Samplecontroller().V1alpha1().Foos()) ppController := proxyprovidercontroller.NewController(ctx, kubeClient, clientset, authentikClient,
proxyProviderInformerFactory.Proxyprovider().V1alpha1().ProxyProviders(),
)
applicationInformerFactory := informers.NewSharedInformerFactory(clientset, time.Second*30)
appController := applicationcontroller.NewController(ctx, kubeClient, clientset, authentikClient,
applicationInformerFactory.Application().V1alpha1().Applications(),
)
policyBindingInformerFactory := informers.NewSharedInformerFactory(clientset, time.Second*30)
pbController := policybindingcontroller.NewController(ctx, kubeClient, clientset, authentikClient,
policyBindingInformerFactory.PolicyBinding().V1alpha1().PolicyBindings(),
)
// notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(ctx.done()) // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(ctx.done())
// Start method is non-blocking and runs all registered informers in a dedicated goroutine. // Start method is non-blocking and runs all registered informers in a dedicated goroutine.
kubeInformerFactory.Start(ctx.Done()) proxyProviderInformerFactory.Start(ctx.Done())
exampleInformerFactory.Start(ctx.Done()) applicationInformerFactory.Start(ctx.Done())
policyBindingInformerFactory.Start(ctx.Done())
if err = controller.Run(ctx, 2); err != nil { var wg sync.WaitGroup
logger.Error(err, "Error running controller") wg.Add(3)
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
} go func() {
defer wg.Done()
if err := ppController.Run(ctx, 2); err != nil {
logger.Error(err, "Error running proxy provider controller")
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}
}()
go func() {
defer wg.Done()
if err := appController.Run(ctx, 2); err != nil {
logger.Error(err, "Error running application controller")
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}
}()
go func() {
defer wg.Done()
if err := pbController.Run(ctx, 2); err != nil {
logger.Error(err, "Error running policy binding controller")
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
}
}()
wg.Wait()
} }
func init() { func init() {
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.") flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
} }
// newAuthentikAPIClient builds the OpenAPI-generated goauthentik client when AUTENTIK_HOST is set.
func newAuthentikAPIClient(host, token string) (*authentikapi.APIClient, error) {
if host == "" {
return nil, errors.New("authentik host is not set")
}
cfg := authentikapi.NewConfiguration()
if u, err := url.Parse(host); err == nil && u.Host != "" {
cfg.Scheme = u.Scheme
if cfg.Scheme == "" {
cfg.Scheme = "https"
}
cfg.Host = u.Host
} else {
cfg.Scheme = "https"
cfg.Host = host
}
if token == "" {
return nil, errors.New("authentik token is not set")
}
cfg.AddDefaultHeader("Authorization", "Bearer "+token)
return authentikapi.NewAPIClient(cfg), nil
}
@@ -1,7 +1,5 @@
//go:build tools
/* /*
Copyright 2019 The Kubernetes Authors. Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -16,7 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// This package imports things required by build scripts, to force `go mod` to see them as dependencies // +k8s:deepcopy-gen=package
package tools // +k8s:openapi-gen=true
// +groupName=application.t000-n.de
// +groupGoName=Application
import _ "k8s.io/code-generator" // Package v1alpha1 is the v1alpha1 version of the application API.
package v1alpha1
@@ -21,34 +21,32 @@ import (
) )
// +genclient // +genclient
// +kubebuilder:subresource:status
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Foo is a specification for a Foo resource type Application struct {
type Foo struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"` metav1.ObjectMeta `json:"metadata,omitempty"`
Spec FooSpec `json:"spec"` Spec ApplicationSpec `json:"spec"`
Status FooStatus `json:"status"` Status ApplicationStatus `json:"status"`
} }
// FooSpec is the spec for a Foo resource type ApplicationSpec struct {
type FooSpec struct { Name string `json:"name"`
DeploymentName string `json:"deploymentName"` Slug string `json:"slug"`
Replicas *int32 `json:"replicas"` Provider int32 `json:"provider,omitempty"`
} }
// FooStatus is the status for a Foo resource type ApplicationStatus struct {
type FooStatus struct { PK string `json:"pk"`
AvailableReplicas int32 `json:"availableReplicas"`
} }
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// FooList is a list of Foo resources type ApplicationList struct {
type FooList struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"` metav1.ListMeta `json:"metadata,omitempty"`
Items []Foo `json:"items"` Items []Application `json:"items"`
} }
@@ -26,27 +26,27 @@ import (
) )
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Foo) DeepCopyInto(out *Foo) { func (in *Application) DeepCopyInto(out *Application) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec) out.Spec = in.Spec
out.Status = in.Status out.Status = in.Status
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Foo. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Application.
func (in *Foo) DeepCopy() *Foo { func (in *Application) DeepCopy() *Application {
if in == nil { if in == nil {
return nil return nil
} }
out := new(Foo) out := new(Application)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Foo) DeepCopyObject() runtime.Object { func (in *Application) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil { if c := in.DeepCopy(); c != nil {
return c return c
} }
@@ -54,13 +54,13 @@ func (in *Foo) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FooList) DeepCopyInto(out *FooList) { func (in *ApplicationList) DeepCopyInto(out *ApplicationList) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta) in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil { if in.Items != nil {
in, out := &in.Items, &out.Items in, out := &in.Items, &out.Items
*out = make([]Foo, len(*in)) *out = make([]Application, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@@ -68,18 +68,18 @@ func (in *FooList) DeepCopyInto(out *FooList) {
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooList. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationList.
func (in *FooList) DeepCopy() *FooList { func (in *ApplicationList) DeepCopy() *ApplicationList {
if in == nil { if in == nil {
return nil return nil
} }
out := new(FooList) out := new(ApplicationList)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *FooList) DeepCopyObject() runtime.Object { func (in *ApplicationList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil { if c := in.DeepCopy(); c != nil {
return c return c
} }
@@ -87,38 +87,33 @@ func (in *FooList) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FooSpec) DeepCopyInto(out *FooSpec) { func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) {
*out = *in *out = *in
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
*out = new(int32)
**out = **in
}
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSpec.
func (in *FooSpec) DeepCopy() *FooSpec { func (in *ApplicationSpec) DeepCopy() *ApplicationSpec {
if in == nil { if in == nil {
return nil return nil
} }
out := new(FooSpec) out := new(ApplicationSpec)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FooStatus) DeepCopyInto(out *FooStatus) { func (in *ApplicationStatus) DeepCopyInto(out *ApplicationStatus) {
*out = *in *out = *in
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooStatus. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationStatus.
func (in *FooStatus) DeepCopy() *FooStatus { func (in *ApplicationStatus) DeepCopy() *ApplicationStatus {
if in == nil { if in == nil {
return nil return nil
} }
out := new(FooStatus) out := new(ApplicationStatus)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
@@ -28,7 +28,7 @@ import (
) )
// GroupName specifies the group name used to register the objects. // GroupName specifies the group name used to register the objects.
const GroupName = "samplecontroller.k8s.io" const GroupName = "application.t000-n.de"
// GroupVersion specifies the group and the version used to register the objects. // GroupVersion specifies the group and the version used to register the objects.
var GroupVersion = v1.GroupVersion{Group: GroupName, Version: "v1alpha1"} var GroupVersion = v1.GroupVersion{Group: GroupName, Version: "v1alpha1"}
@@ -62,8 +62,8 @@ func init() {
// Adds the list of known types to Scheme. // Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error { func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
&Foo{}, &Application{},
&FooList{}, &ApplicationList{},
) )
// AddToGroupVersion allows the serialization of client types like ListOptions. // AddToGroupVersion allows the serialization of client types like ListOptions.
v1.AddToGroupVersion(scheme, SchemeGroupVersion) v1.AddToGroupVersion(scheme, SchemeGroupVersion)
+23
View File
@@ -0,0 +1,23 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +groupName=policybinding.t000-n.de
// +groupGoName=PolicyBinding
// Package v1alpha1 is the v1alpha1 version of the policybinding API.
package v1alpha1
+54
View File
@@ -0,0 +1,54 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +kubebuilder:subresource:status
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type PolicyBinding struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec PolicyBindingSpec `json:"spec"`
Status PolicyBindingStatus `json:"status"`
}
type PolicyBindingSpec struct {
Policy string `json:"policy,omitempty"`
Group string `json:"group,omitempty"`
User int32 `json:"user,omitempty"`
Target string `json:"target"`
Order int32 `json:"order"`
}
type PolicyBindingStatus struct {
PK string `json:"pk"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type PolicyBindingList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []PolicyBinding `json:"items"`
}
@@ -0,0 +1,119 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyBinding) DeepCopyInto(out *PolicyBinding) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyBinding.
func (in *PolicyBinding) DeepCopy() *PolicyBinding {
if in == nil {
return nil
}
out := new(PolicyBinding)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PolicyBinding) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyBindingList) DeepCopyInto(out *PolicyBindingList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]PolicyBinding, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyBindingList.
func (in *PolicyBindingList) DeepCopy() *PolicyBindingList {
if in == nil {
return nil
}
out := new(PolicyBindingList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PolicyBindingList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyBindingSpec) DeepCopyInto(out *PolicyBindingSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyBindingSpec.
func (in *PolicyBindingSpec) DeepCopy() *PolicyBindingSpec {
if in == nil {
return nil
}
out := new(PolicyBindingSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyBindingStatus) DeepCopyInto(out *PolicyBindingStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyBindingStatus.
func (in *PolicyBindingStatus) DeepCopy() *PolicyBindingStatus {
if in == nil {
return nil
}
out := new(PolicyBindingStatus)
in.DeepCopyInto(out)
return out
}
@@ -0,0 +1,71 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by register-gen. DO NOT EDIT.
package v1alpha1
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName specifies the group name used to register the objects.
const GroupName = "policybinding.t000-n.de"
// GroupVersion specifies the group and the version used to register the objects.
var GroupVersion = v1.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// SchemeGroupVersion is group version used to register these objects
//
// Deprecated: use GroupVersion instead.
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
// Deprecated: use Install instead
AddToScheme = localSchemeBuilder.AddToScheme
Install = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes)
}
// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&PolicyBinding{},
&PolicyBindingList{},
)
// AddToGroupVersion allows the serialization of client types like ListOptions.
v1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
@@ -16,7 +16,7 @@ limitations under the License.
// +k8s:deepcopy-gen=package // +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true // +k8s:openapi-gen=true
// +groupName=samplecontroller.k8s.io // +groupName=proxyprovider.t000-n.de
// Package v1alpha1 is the v1alpha1 version of the API. // Package v1 is the v1 version of the API.
package v1alpha1 package v1alpha1
+54
View File
@@ -0,0 +1,54 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +kubebuilder:subresource:status
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ProxyProvider struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ProxyProviderSpec `json:"spec"`
Status ProxyProviderStatus `json:"status"`
}
type ProxyProviderSpec struct {
Name string `json:"name"`
AuthorizationFlow string `json:"authorization_flow"`
InvalidationFlow string `json:"invalidation_flow"`
ExternalHost string `json:"external_host"`
Outpost string `json:"outpost"`
}
type ProxyProviderStatus struct {
PK string `json:"pk"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ProxyProviderList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ProxyProvider `json:"items"`
}
@@ -0,0 +1,119 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProxyProvider) DeepCopyInto(out *ProxyProvider) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyProvider.
func (in *ProxyProvider) DeepCopy() *ProxyProvider {
if in == nil {
return nil
}
out := new(ProxyProvider)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ProxyProvider) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProxyProviderList) DeepCopyInto(out *ProxyProviderList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]ProxyProvider, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyProviderList.
func (in *ProxyProviderList) DeepCopy() *ProxyProviderList {
if in == nil {
return nil
}
out := new(ProxyProviderList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ProxyProviderList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProxyProviderSpec) DeepCopyInto(out *ProxyProviderSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyProviderSpec.
func (in *ProxyProviderSpec) DeepCopy() *ProxyProviderSpec {
if in == nil {
return nil
}
out := new(ProxyProviderSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProxyProviderStatus) DeepCopyInto(out *ProxyProviderStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyProviderStatus.
func (in *ProxyProviderStatus) DeepCopy() *ProxyProviderStatus {
if in == nil {
return nil
}
out := new(ProxyProviderStatus)
in.DeepCopyInto(out)
return out
}
@@ -0,0 +1,71 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by register-gen. DO NOT EDIT.
package v1alpha1
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName specifies the group name used to register the objects.
const GroupName = "proxyprovider.t000-n.de"
// GroupVersion specifies the group and the version used to register the objects.
var GroupVersion = v1.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// SchemeGroupVersion is group version used to register these objects
//
// Deprecated: use GroupVersion instead.
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
// Deprecated: use Install instead
AddToScheme = localSchemeBuilder.AddToScheme
Install = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addKnownTypes)
}
// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&ProxyProvider{},
&ProxyProviderList{},
)
// AddToGroupVersion allows the serialization of client types like ListOptions.
v1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
+230
View File
@@ -0,0 +1,230 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package application
import (
"context"
"fmt"
"net/http"
"slices"
"time"
"golang.org/x/time/rate"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/internal/baseController"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/application/v1alpha1"
listers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/application/v1alpha1"
authentikapi "goauthentik.io/api/v3"
)
const controllerAgentName = "application-controller"
const (
SuccessSynced = "Synced"
ErrResourceExists = "ErrResourceExists"
MessageResourceExists = "Resource %q already exists and is not managed by Application"
MessageResourceSynced = "Application synced successfully"
FieldManager = controllerAgentName
)
// Finalizers
const (
DeleteAuthentikApplicationFinalizer = "application.t000-n.de/delete-authentik-application"
)
type ApplicationController struct {
kubeclientset kubernetes.Interface
applicationClientset clientset.Interface
authentik *authentikapi.APIClient
applicationListener listers.ApplicationLister
controller *baseController.Controller
}
func NewController(
ctx context.Context,
kubeclientset kubernetes.Interface,
applicationClientset clientset.Interface,
authentik *authentikapi.APIClient,
applicationInformer informers.ApplicationInformer,
) *ApplicationController {
logger := klog.FromContext(ctx)
utilruntime.Must(operatorscheme.AddToScheme(scheme.Scheme))
logger.V(4).Info("Creating event broadcaster")
eventBroadcaster := record.NewBroadcaster(record.WithContext(ctx))
eventBroadcaster.StartStructuredLogging(0)
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
ratelimiter := workqueue.NewTypedMaxOfRateLimiter(
workqueue.NewTypedItemExponentialFailureRateLimiter[cache.ObjectName](5*time.Millisecond, 1000*time.Second),
&workqueue.TypedBucketRateLimiter[cache.ObjectName]{Limiter: rate.NewLimiter(rate.Limit(50), 300)},
)
c := &ApplicationController{
kubeclientset: kubeclientset,
applicationClientset: applicationClientset,
authentik: authentik,
applicationListener: applicationInformer.Lister(),
}
c.controller = baseController.NewController(
ctx,
workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder,
applicationInformer.Informer().HasSynced,
c.syncHandler,
)
logger.Info("Setting up event handlers")
applicationInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.controller.Enqueue,
UpdateFunc: func(_, newObj interface{}) {
c.controller.Enqueue(newObj)
},
})
return c
}
func (c *ApplicationController) Run(ctx context.Context, workers int) error {
return c.controller.Run(ctx, workers)
}
func (c *ApplicationController) syncHandler(ctx context.Context, objectRef cache.ObjectName) error {
logger := klog.LoggerWithValues(klog.FromContext(ctx), "objectRef", objectRef)
app, err := c.applicationListener.Applications(objectRef.Namespace).Get(objectRef.Name)
if err != nil {
if errors.IsNotFound(err) {
logger.V(4).Info("Application no longer exists")
return nil
}
return err
}
logger.V(4).Info("sync Application", "name", app.Name)
if !app.ObjectMeta.DeletionTimestamp.IsZero() {
logger.Info("Reconciling deletion of Application", "name", app.Name)
return c.reconcileDelete(ctx, app)
}
if app.Status.PK == "" {
logger.Info("Reconciling creation of Application", "name", app.Name)
return c.reconcileCreate(ctx, app)
}
// Check if all finalizers are present. If not, we add them. Same pattern as above, just needs a helper function to check for presence of a finalizer.
if !slices.Contains(app.ObjectMeta.Finalizers, DeleteAuthentikApplicationFinalizer) {
logger.Info("Ensuring finalizers are present", "name", app.Name)
return c.ensureFinalizers(ctx, app)
}
logger.Info("Reconciling update of Application", "name", app.Name)
return c.reconcileUpdate(ctx, app)
}
func (c *ApplicationController) ensureFinalizers(ctx context.Context, app *v1alpha1.Application) error {
app.ObjectMeta.Finalizers = append(app.ObjectMeta.Finalizers, DeleteAuthentikApplicationFinalizer)
return c.updateApplication(ctx, app)
}
func (c *ApplicationController) reconcileDelete(ctx context.Context, app *v1alpha1.Application) error {
r, err := c.authentik.CoreApi.CoreApplicationsDestroy(ctx, app.Spec.Slug).Execute()
if err != nil {
// This handles an edge-case, where when the Application on Authentik has already been deleted, but the finalizer is still present. We just remove the finalizer and return.
if r != nil && r.StatusCode != http.StatusNotFound {
return fmt.Errorf("error when calling `CoreAPI.CoreApplicationsDestroy`: %w with response %v", err, r)
}
}
app.ObjectMeta.Finalizers = slices.Delete(app.ObjectMeta.Finalizers, slices.Index(app.ObjectMeta.Finalizers, DeleteAuthentikApplicationFinalizer), 1)
return c.updateApplication(ctx, app)
}
func (c *ApplicationController) reconcileUpdate(ctx context.Context, app *v1alpha1.Application) error {
_, r, err := c.authentik.CoreApi.CoreApplicationsRetrieve(ctx, app.Spec.Slug).Execute()
if err != nil {
if r != nil && r.StatusCode == http.StatusNotFound {
// This handles an edge-case, where when the Application on Authentik has been deleted, e.g. by mistake. We just remove the PK and return.
// During the next reconciliation, the Application will be re-created.
app.Status.PK = ""
return c.updateApplicationStatus(ctx, app)
}
return fmt.Errorf("error retrieving existing Application: %v with response %v", err, r)
}
patchedApplicationRequest := &authentikapi.PatchedApplicationRequest{
Name: &app.Spec.Name,
Slug: &app.Spec.Slug,
Provider: *authentikapi.NewNullableInt32(&app.Spec.Provider),
}
resp, r, err := c.authentik.CoreApi.CoreApplicationsPartialUpdate(ctx, app.Spec.Slug).PatchedApplicationRequest(*patchedApplicationRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `CoreAPI.CoreApplicationsPartialUpdate`: %w with response %v", err, r)
}
app.Status.PK = resp.Pk
return c.updateApplicationStatus(ctx, app)
}
func (c *ApplicationController) reconcileCreate(ctx context.Context, app *v1alpha1.Application) error {
applicationRequest := &authentikapi.ApplicationRequest{
Name: app.Spec.Name,
Slug: app.Spec.Slug,
Provider: *authentikapi.NewNullableInt32(&app.Spec.Provider),
}
resp, r, err := c.authentik.CoreApi.CoreApplicationsCreate(ctx).ApplicationRequest(*applicationRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `CoreAPI.CoreApplicationsCreate`: %w with response %v", err, r)
}
app.Status.PK = resp.Pk
return c.updateApplicationStatus(ctx, app)
}
func (c *ApplicationController) updateApplicationStatus(ctx context.Context, app *v1alpha1.Application) error {
appCopy := app.DeepCopy()
_, err := c.applicationClientset.ApplicationV1alpha1().Applications(appCopy.Namespace).UpdateStatus(ctx, appCopy, metav1.UpdateOptions{FieldManager: FieldManager})
return err
}
// Update metadata, spec, etc. of the Application object.
func (c *ApplicationController) updateApplication(ctx context.Context, app *v1alpha1.Application) error {
appCopy := app.DeepCopy()
_, err := c.applicationClientset.ApplicationV1alpha1().Applications(appCopy.Namespace).Update(ctx, appCopy, metav1.UpdateOptions{FieldManager: FieldManager})
if err != nil {
return fmt.Errorf("error updating Application metadata: %v", err)
}
return nil
}
@@ -0,0 +1,377 @@
// AI generated tests and not yet reviewed.
package application
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"slices"
"strings"
"testing"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
operatorfake "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/fake"
operatorinformers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions"
authentikapi "goauthentik.io/api/v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"
)
func TestController_syncHandler_create(t *testing.T) {
const wantPK = "42"
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationCreate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusCreated, map[string]any{"pk": wantPK})
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, testApplication(), server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "test-app"})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getApplication(t, ctrl, "default", "test-app")
if got.Status.PK != wantPK {
t.Fatalf("status.pk = %q, want %q", got.Status.PK, wantPK)
}
}
func TestController_syncHandler_ensureFinalizers(t *testing.T) {
app := testApplication()
app.Status.PK = "42"
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getApplication(t, ctrl, app.Namespace, app.Name)
if !slices.Contains(got.Finalizers, DeleteAuthentikApplicationFinalizer) {
t.Fatalf("finalizers = %v, want %q", got.Finalizers, DeleteAuthentikApplicationFinalizer)
}
}
func TestController_syncHandler_update(t *testing.T) {
app := testApplication()
app.Status.PK = "42"
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationRetrieve: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{"pk": "42"})
},
applicationPartialUpdate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{"pk": "42"})
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getApplication(t, ctrl, app.Namespace, app.Name)
if got.Status.PK != "42" {
t.Fatalf("status.pk = %q, want 42", got.Status.PK)
}
}
func TestController_syncHandler_update_applicationNotFound(t *testing.T) {
app := testApplication()
app.Status.PK = "42"
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationRetrieve: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getApplication(t, ctrl, app.Namespace, app.Name)
if got.Status.PK != "" {
t.Fatalf("status.pk = %q, want empty after application not found", got.Status.PK)
}
}
func TestController_syncHandler_delete(t *testing.T) {
now := metav1.Now()
app := testApplication()
app.Status.PK = "42"
app.DeletionTimestamp = &now
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
var destroyCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationDestroy: func(w http.ResponseWriter, r *http.Request) {
destroyCalled = true
if r.Method != http.MethodDelete {
t.Errorf("destroy method = %s, want DELETE", r.Method)
}
w.WriteHeader(http.StatusNoContent)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if !destroyCalled {
t.Fatal("expected Authentik destroy call")
}
got := getApplication(t, ctrl, app.Namespace, app.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikApplicationFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed", got.Finalizers)
}
}
func TestController_syncHandler_delete_providerAlreadyGone(t *testing.T) {
now := metav1.Now()
app := testApplication()
app.Status.PK = "42"
app.DeletionTimestamp = &now
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationDestroy: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getApplication(t, ctrl, app.Namespace, app.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikApplicationFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed after 404", got.Finalizers)
}
}
func TestController_syncHandler_notFound(t *testing.T) {
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, nil, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "missing"})
if err != nil {
t.Fatalf("syncHandler() error = %v, want nil for missing object", err)
}
}
func TestController_syncHandler_delete_usesSlugNotPK(t *testing.T) {
now := metav1.Now()
app := testApplication()
app.Status.PK = "not-a-number"
app.DeletionTimestamp = &now
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
var destroySlug string
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationDestroy: func(w http.ResponseWriter, r *http.Request) {
destroySlug = strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/api/v3/core/applications/"), "/")
w.WriteHeader(http.StatusNoContent)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if destroySlug != app.Spec.Slug {
t.Fatalf("destroy slug = %q, want %q (delete must use spec.slug, not status.pk)", destroySlug, app.Spec.Slug)
}
}
// --- test helpers ---
func testApplication() *v1alpha1.Application {
return &v1alpha1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-app",
Namespace: "default",
},
Spec: v1alpha1.ApplicationSpec{
Name: "My Application",
Slug: "my-app",
Provider: 7,
},
}
}
func newTestController(t *testing.T, app *v1alpha1.Application, authentikURL string) (*ApplicationController, context.Context, context.CancelFunc) {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
ctrl, _, stop := newTestControllerWithContext(t, ctx, app, authentikURL)
return ctrl, ctx, func() {
cancel()
stop()
}
}
func newTestControllerWithContext(t *testing.T, ctx context.Context, app *v1alpha1.Application, authentikURL string) (*ApplicationController, context.Context, func()) {
t.Helper()
authentikClient := newAuthentikAPIClientForTest(t, authentikURL)
var objects []runtime.Object
if app != nil {
objects = append(objects, app)
}
applicationClient := operatorfake.NewSimpleClientset(objects...)
informerFactory := operatorinformers.NewSharedInformerFactory(applicationClient, 0)
applicationInformer := informerFactory.Application().V1alpha1().Applications()
ctrl := NewController(ctx, fake.NewClientset(), applicationClient, authentikClient, applicationInformer)
informerFactory.Start(ctx.Done())
for informerType, synced := range informerFactory.WaitForCacheSync(ctx.Done()) {
if !synced {
t.Fatalf("informer %v failed to sync", informerType)
}
}
return ctrl, ctx, func() {}
}
func newAuthentikAPIClientForTest(t *testing.T, serverURL string) *authentikapi.APIClient {
t.Helper()
u, err := url.Parse(serverURL)
if err != nil {
t.Fatalf("parse server URL: %v", err)
}
cfg := authentikapi.NewConfiguration()
cfg.Scheme = u.Scheme
cfg.Host = u.Host
return authentikapi.NewAPIClient(cfg)
}
type authentikTestHandlers struct {
applicationCreate http.HandlerFunc
applicationRetrieve http.HandlerFunc
applicationPartialUpdate http.HandlerFunc
applicationDestroy http.HandlerFunc
}
func newAuthentikTestServer(t *testing.T, handlers authentikTestHandlers) *httptest.Server {
t.Helper()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
switch {
case path == "/api/v3/core/applications/" && r.Method == http.MethodPost:
if handlers.applicationCreate != nil {
handlers.applicationCreate(w, r)
return
}
http.NotFound(w, r)
case strings.HasPrefix(path, "/api/v3/core/applications/") && strings.HasSuffix(path, "/"):
slugPath := strings.TrimPrefix(path, "/api/v3/core/applications/")
if slugPath == "" {
http.NotFound(w, r)
return
}
switch r.Method {
case http.MethodGet:
if handlers.applicationRetrieve != nil {
handlers.applicationRetrieve(w, r)
return
}
http.NotFound(w, r)
case http.MethodPatch:
if handlers.applicationPartialUpdate != nil {
handlers.applicationPartialUpdate(w, r)
return
}
http.NotFound(w, r)
case http.MethodDelete:
if handlers.applicationDestroy != nil {
handlers.applicationDestroy(w, r)
return
}
http.NotFound(w, r)
default:
http.Error(w, "unexpected method on application instance", http.StatusMethodNotAllowed)
}
default:
http.NotFound(w, r)
}
})
return httptest.NewServer(handler)
}
func writeJSON(t *testing.T, w http.ResponseWriter, status int, body any) {
t.Helper()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if err := json.NewEncoder(w).Encode(body); err != nil {
t.Fatalf("write JSON response: %v", err)
}
}
func getApplication(t *testing.T, ctrl *ApplicationController, namespace, name string) *v1alpha1.Application {
t.Helper()
got, err := ctrl.applicationClientset.ApplicationV1alpha1().Applications(namespace).Get(
context.Background(), name, metav1.GetOptions{},
)
if err != nil {
t.Fatalf("get Application: %v", err)
}
return got
}
+245
View File
@@ -0,0 +1,245 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package policybinding
import (
"context"
"fmt"
"net/http"
"slices"
"time"
"golang.org/x/time/rate"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/internal/baseController"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/policybinding/v1alpha1"
listers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/policybinding/v1alpha1"
authentikapi "goauthentik.io/api/v3"
)
const controllerAgentName = "policybinding-controller"
const (
SuccessSynced = "Synced"
ErrResourceExists = "ErrResourceExists"
MessageResourceExists = "Resource %q already exists and is not managed by PolicyBinding"
MessageResourceSynced = "PolicyBinding synced successfully"
FieldManager = controllerAgentName
)
// Finalizers
const (
DeleteAuthentikPolicyBindingFinalizer = "policybinding.t000-n.de/delete-authentik-policybinding"
)
type PolicyBindingController struct {
kubeclientset kubernetes.Interface
policyBindingClientset clientset.Interface
authentik *authentikapi.APIClient
policyBindingListener listers.PolicyBindingLister
controller *baseController.Controller
}
func NewController(
ctx context.Context,
kubeclientset kubernetes.Interface,
policyBindingClientset clientset.Interface,
authentik *authentikapi.APIClient,
policyBindingInformer informers.PolicyBindingInformer,
) *PolicyBindingController {
logger := klog.FromContext(ctx)
utilruntime.Must(operatorscheme.AddToScheme(scheme.Scheme))
logger.V(4).Info("Creating event broadcaster")
eventBroadcaster := record.NewBroadcaster(record.WithContext(ctx))
eventBroadcaster.StartStructuredLogging(0)
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
ratelimiter := workqueue.NewTypedMaxOfRateLimiter(
workqueue.NewTypedItemExponentialFailureRateLimiter[cache.ObjectName](5*time.Millisecond, 1000*time.Second),
&workqueue.TypedBucketRateLimiter[cache.ObjectName]{Limiter: rate.NewLimiter(rate.Limit(50), 300)},
)
c := &PolicyBindingController{
kubeclientset: kubeclientset,
policyBindingClientset: policyBindingClientset,
authentik: authentik,
policyBindingListener: policyBindingInformer.Lister(),
}
c.controller = baseController.NewController(
ctx,
workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder,
policyBindingInformer.Informer().HasSynced,
c.syncHandler,
)
logger.Info("Setting up event handlers")
policyBindingInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.controller.Enqueue,
UpdateFunc: func(_, newObj interface{}) {
c.controller.Enqueue(newObj)
},
})
return c
}
func (c *PolicyBindingController) Run(ctx context.Context, workers int) error {
return c.controller.Run(ctx, workers)
}
func (c *PolicyBindingController) syncHandler(ctx context.Context, objectRef cache.ObjectName) error {
logger := klog.LoggerWithValues(klog.FromContext(ctx), "objectRef", objectRef)
pb, err := c.policyBindingListener.PolicyBindings(objectRef.Namespace).Get(objectRef.Name)
if err != nil {
if errors.IsNotFound(err) {
logger.V(4).Info("PolicyBinding no longer exists")
return nil
}
return err
}
logger.V(4).Info("sync PolicyBinding", "name", pb.Name)
if !pb.ObjectMeta.DeletionTimestamp.IsZero() {
logger.Info("Reconciling deletion of PolicyBinding", "name", pb.Name)
return c.reconcileDelete(ctx, pb)
}
if pb.Status.PK == "" {
logger.Info("Reconciling creation of PolicyBinding", "name", pb.Name)
return c.reconcileCreate(ctx, pb)
}
// Check if all finalizers are present. If not, we add them. Same pattern as above, just needs a helper function to check for presence of a finalizer.
if !slices.Contains(pb.ObjectMeta.Finalizers, DeleteAuthentikPolicyBindingFinalizer) {
logger.Info("Ensuring finalizers are present", "name", pb.Name)
return c.ensureFinalizers(ctx, pb)
}
logger.Info("Reconciling update of PolicyBinding", "name", pb.Name)
return c.reconcileUpdate(ctx, pb)
}
func (c *PolicyBindingController) ensureFinalizers(ctx context.Context, pb *v1alpha1.PolicyBinding) error {
pb.ObjectMeta.Finalizers = append(pb.ObjectMeta.Finalizers, DeleteAuthentikPolicyBindingFinalizer)
return c.updatePolicyBinding(ctx, pb)
}
func (c *PolicyBindingController) reconcileDelete(ctx context.Context, pb *v1alpha1.PolicyBinding) error {
r, err := c.authentik.PoliciesApi.PoliciesBindingsDestroy(ctx, pb.Status.PK).Execute()
if err != nil {
// This handles an edge-case, where when the PolicyBinding on Authentik has already been deleted, but the finalizer is still present. We just remove the finalizer and return.
if r != nil && r.StatusCode != http.StatusNotFound {
return fmt.Errorf("error when calling `PoliciesAPI.PoliciesBindingsDestroy`: %w with response %v", err, r)
}
}
pb.ObjectMeta.Finalizers = slices.Delete(pb.ObjectMeta.Finalizers, slices.Index(pb.ObjectMeta.Finalizers, DeleteAuthentikPolicyBindingFinalizer), 1)
return c.updatePolicyBinding(ctx, pb)
}
func (c *PolicyBindingController) reconcileUpdate(ctx context.Context, pb *v1alpha1.PolicyBinding) error {
_, r, err := c.authentik.PoliciesApi.PoliciesBindingsRetrieve(ctx, pb.Status.PK).Execute()
if err != nil {
if r != nil && r.StatusCode == http.StatusNotFound {
// This handles an edge-case, where when the PolicyBinding on Authentik has been deleted, e.g. by mistake. We just remove the PK and return.
// During the next reconciliation, the PolicyBinding will be re-created.
pb.Status.PK = ""
return c.updatePolicyBindingStatus(ctx, pb)
}
return fmt.Errorf("error retrieving existing PolicyBinding: %v with response %v", err, r)
}
patchedPolicyBindingRequest := &authentikapi.PatchedPolicyBindingRequest{
Target: &pb.Spec.Target,
Order: &pb.Spec.Order,
}
if pb.Spec.Policy != "" {
patchedPolicyBindingRequest.SetPolicy(pb.Spec.Policy)
}
if pb.Spec.Group != "" {
patchedPolicyBindingRequest.SetGroup(pb.Spec.Group)
}
if pb.Spec.User != 0 {
patchedPolicyBindingRequest.SetUser(pb.Spec.User)
}
resp, r, err := c.authentik.PoliciesApi.PoliciesBindingsPartialUpdate(ctx, pb.Status.PK).PatchedPolicyBindingRequest(*patchedPolicyBindingRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `PoliciesAPI.PoliciesBindingsPartialUpdate`: %w with response %v", err, r)
}
pb.Status.PK = resp.Pk
return c.updatePolicyBindingStatus(ctx, pb)
}
func (c *PolicyBindingController) reconcileCreate(ctx context.Context, pb *v1alpha1.PolicyBinding) error {
policyBindingRequest := &authentikapi.PolicyBindingRequest{
Target: pb.Spec.Target,
Order: pb.Spec.Order,
}
if pb.Spec.Policy != "" {
policyBindingRequest.SetPolicy(pb.Spec.Policy)
}
if pb.Spec.Group != "" {
policyBindingRequest.SetGroup(pb.Spec.Group)
}
if pb.Spec.User != 0 {
policyBindingRequest.SetUser(pb.Spec.User)
}
resp, r, err := c.authentik.PoliciesApi.PoliciesBindingsCreate(ctx).PolicyBindingRequest(*policyBindingRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `PoliciesAPI.PoliciesBindingsCreate`: %w with response %v", err, r)
}
pb.Status.PK = resp.Pk
return c.updatePolicyBindingStatus(ctx, pb)
}
func (c *PolicyBindingController) updatePolicyBindingStatus(ctx context.Context, pb *v1alpha1.PolicyBinding) error {
pbCopy := pb.DeepCopy()
_, err := c.policyBindingClientset.PolicyBindingV1alpha1().PolicyBindings(pbCopy.Namespace).UpdateStatus(ctx, pbCopy, metav1.UpdateOptions{FieldManager: FieldManager})
return err
}
// Update metadata, spec, etc. of the PolicyBinding object.
func (c *PolicyBindingController) updatePolicyBinding(ctx context.Context, pb *v1alpha1.PolicyBinding) error {
pbCopy := pb.DeepCopy()
_, err := c.policyBindingClientset.PolicyBindingV1alpha1().PolicyBindings(pbCopy.Namespace).Update(ctx, pbCopy, metav1.UpdateOptions{FieldManager: FieldManager})
return err
}
@@ -0,0 +1,349 @@
// AI generated tests and not yet reviewed.
package policybinding
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"slices"
"strings"
"testing"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
operatorfake "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/fake"
operatorinformers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions"
authentikapi "goauthentik.io/api/v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"
)
func TestController_syncHandler_create(t *testing.T) {
const wantPK = "42"
server := newAuthentikTestServer(t, authentikTestHandlers{
policyBindingCreate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusCreated, map[string]any{"pk": wantPK})
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, testPolicyBinding(), server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "test-pb"})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getPolicyBinding(t, ctrl, "default", "test-pb")
if got.Status.PK != wantPK {
t.Fatalf("status.pk = %q, want %q", got.Status.PK, wantPK)
}
}
func TestController_syncHandler_ensureFinalizers(t *testing.T) {
pb := testPolicyBinding()
pb.Status.PK = "42"
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pb, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pb.Namespace, Name: pb.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getPolicyBinding(t, ctrl, pb.Namespace, pb.Name)
if !slices.Contains(got.Finalizers, DeleteAuthentikPolicyBindingFinalizer) {
t.Fatalf("finalizers = %v, want %q", got.Finalizers, DeleteAuthentikPolicyBindingFinalizer)
}
}
func TestController_syncHandler_update(t *testing.T) {
pb := testPolicyBinding()
pb.Status.PK = "42"
pb.Finalizers = []string{DeleteAuthentikPolicyBindingFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
policyBindingRetrieve: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{"pk": "42"})
},
policyBindingPartialUpdate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{"pk": "42"})
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pb, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pb.Namespace, Name: pb.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getPolicyBinding(t, ctrl, pb.Namespace, pb.Name)
if got.Status.PK != "42" {
t.Fatalf("status.pk = %q, want 42", got.Status.PK)
}
}
func TestController_syncHandler_update_policyBindingNotFound(t *testing.T) {
pb := testPolicyBinding()
pb.Status.PK = "42"
pb.Finalizers = []string{DeleteAuthentikPolicyBindingFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
policyBindingRetrieve: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pb, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pb.Namespace, Name: pb.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getPolicyBinding(t, ctrl, pb.Namespace, pb.Name)
if got.Status.PK != "" {
t.Fatalf("status.pk = %q, want empty after policy binding not found", got.Status.PK)
}
}
func TestController_syncHandler_delete(t *testing.T) {
now := metav1.Now()
pb := testPolicyBinding()
pb.Status.PK = "42"
pb.DeletionTimestamp = &now
pb.Finalizers = []string{DeleteAuthentikPolicyBindingFinalizer}
var destroyCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
policyBindingDestroy: func(w http.ResponseWriter, r *http.Request) {
destroyCalled = true
if r.Method != http.MethodDelete {
t.Errorf("destroy method = %s, want DELETE", r.Method)
}
w.WriteHeader(http.StatusNoContent)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pb, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pb.Namespace, Name: pb.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if !destroyCalled {
t.Fatal("expected Authentik destroy call")
}
got := getPolicyBinding(t, ctrl, pb.Namespace, pb.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikPolicyBindingFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed", got.Finalizers)
}
}
func TestController_syncHandler_delete_policyBindingAlreadyGone(t *testing.T) {
now := metav1.Now()
pb := testPolicyBinding()
pb.Status.PK = "42"
pb.DeletionTimestamp = &now
pb.Finalizers = []string{DeleteAuthentikPolicyBindingFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
policyBindingDestroy: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pb, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pb.Namespace, Name: pb.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getPolicyBinding(t, ctrl, pb.Namespace, pb.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikPolicyBindingFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed after 404", got.Finalizers)
}
}
func TestController_syncHandler_notFound(t *testing.T) {
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, nil, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "missing"})
if err != nil {
t.Fatalf("syncHandler() error = %v, want nil for missing object", err)
}
}
// --- test helpers ---
func testPolicyBinding() *v1alpha1.PolicyBinding {
return &v1alpha1.PolicyBinding{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: "PolicyBinding",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-pb",
Namespace: "default",
},
Spec: v1alpha1.PolicyBindingSpec{
Group: "14ab813f-a7f9-481b-9b08-781953ae9ebf",
Target: "8dd85627-9c48-49c2-8afc-d73dd122ffc2",
Order: 1,
},
}
}
func newTestController(t *testing.T, pb *v1alpha1.PolicyBinding, authentikURL string) (*PolicyBindingController, context.Context, context.CancelFunc) {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
ctrl, _, stop := newTestControllerWithContext(t, ctx, pb, authentikURL)
return ctrl, ctx, func() {
cancel()
stop()
}
}
func newTestControllerWithContext(t *testing.T, ctx context.Context, pb *v1alpha1.PolicyBinding, authentikURL string) (*PolicyBindingController, context.Context, func()) {
t.Helper()
authentikClient := newAuthentikAPIClientForTest(t, authentikURL)
var objects []runtime.Object
if pb != nil {
objects = append(objects, pb)
}
policyBindingClient := operatorfake.NewSimpleClientset(objects...)
informerFactory := operatorinformers.NewSharedInformerFactory(policyBindingClient, 0)
policyBindingInformer := informerFactory.PolicyBinding().V1alpha1().PolicyBindings()
ctrl := NewController(ctx, fake.NewClientset(), policyBindingClient, authentikClient, policyBindingInformer)
informerFactory.Start(ctx.Done())
for informerType, synced := range informerFactory.WaitForCacheSync(ctx.Done()) {
if !synced {
t.Fatalf("informer %v failed to sync", informerType)
}
}
return ctrl, ctx, func() {}
}
func newAuthentikAPIClientForTest(t *testing.T, serverURL string) *authentikapi.APIClient {
t.Helper()
u, err := url.Parse(serverURL)
if err != nil {
t.Fatalf("parse server URL: %v", err)
}
cfg := authentikapi.NewConfiguration()
cfg.Scheme = u.Scheme
cfg.Host = u.Host
return authentikapi.NewAPIClient(cfg)
}
type authentikTestHandlers struct {
policyBindingCreate http.HandlerFunc
policyBindingRetrieve http.HandlerFunc
policyBindingPartialUpdate http.HandlerFunc
policyBindingDestroy http.HandlerFunc
}
func newAuthentikTestServer(t *testing.T, handlers authentikTestHandlers) *httptest.Server {
t.Helper()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
switch {
case path == "/api/v3/policies/bindings/" && r.Method == http.MethodPost:
if handlers.policyBindingCreate != nil {
handlers.policyBindingCreate(w, r)
return
}
http.NotFound(w, r)
case strings.HasPrefix(path, "/api/v3/policies/bindings/") && strings.HasSuffix(path, "/"):
idPath := strings.TrimPrefix(path, "/api/v3/policies/bindings/")
if idPath == "" {
http.NotFound(w, r)
return
}
switch r.Method {
case http.MethodGet:
if handlers.policyBindingRetrieve != nil {
handlers.policyBindingRetrieve(w, r)
return
}
http.NotFound(w, r)
case http.MethodPatch:
if handlers.policyBindingPartialUpdate != nil {
handlers.policyBindingPartialUpdate(w, r)
return
}
http.NotFound(w, r)
case http.MethodDelete:
if handlers.policyBindingDestroy != nil {
handlers.policyBindingDestroy(w, r)
return
}
http.NotFound(w, r)
default:
http.Error(w, "unexpected method on policy binding instance", http.StatusMethodNotAllowed)
}
default:
http.NotFound(w, r)
}
})
return httptest.NewServer(handler)
}
func writeJSON(t *testing.T, w http.ResponseWriter, status int, body any) {
t.Helper()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if err := json.NewEncoder(w).Encode(body); err != nil {
t.Fatalf("write JSON response: %v", err)
}
}
func getPolicyBinding(t *testing.T, ctrl *PolicyBindingController, namespace, name string) *v1alpha1.PolicyBinding {
t.Helper()
got, err := ctrl.policyBindingClientset.PolicyBindingV1alpha1().PolicyBindings(namespace).Get(
context.Background(), name, metav1.GetOptions{},
)
if err != nil {
t.Fatalf("get PolicyBinding: %v", err)
}
return got
}
+309
View File
@@ -0,0 +1,309 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package proxyprovider
import (
"context"
"fmt"
"net/http"
"slices"
"strconv"
"time"
"golang.org/x/time/rate"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/internal/baseController"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/proxyprovider/v1alpha1"
listers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/proxyprovider/v1alpha1"
authentikapi "goauthentik.io/api/v3"
)
const controllerAgentName = "proxy-provider-controller"
const (
SuccessSynced = "Synced"
ErrResourceExists = "ErrResourceExists"
MessageResourceExists = "Resource %q already exists and is not managed by ProxyProvider"
MessageResourceSynced = "ProxyProvider synced successfully"
FieldManager = controllerAgentName
)
// Finalizers
const (
DeleteAuthentikProxyProviderFinalizer = "proxyprovider.t000-n.de/delete-authentik-proxyprovider"
)
type ProxyProviderController struct {
kubeclientset kubernetes.Interface
proxyProviderClientset clientset.Interface
authentik *authentikapi.APIClient
proxyLister listers.ProxyProviderLister
controller *baseController.Controller
}
func NewController(
ctx context.Context,
kubeclientset kubernetes.Interface,
proxyProviderClientset clientset.Interface,
authentik *authentikapi.APIClient,
proxyInformer informers.ProxyProviderInformer,
) *ProxyProviderController {
logger := klog.FromContext(ctx)
utilruntime.Must(operatorscheme.AddToScheme(scheme.Scheme))
logger.V(4).Info("Creating event broadcaster")
eventBroadcaster := record.NewBroadcaster(record.WithContext(ctx))
eventBroadcaster.StartStructuredLogging(0)
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
ratelimiter := workqueue.NewTypedMaxOfRateLimiter(
workqueue.NewTypedItemExponentialFailureRateLimiter[cache.ObjectName](5*time.Millisecond, 1000*time.Second),
&workqueue.TypedBucketRateLimiter[cache.ObjectName]{Limiter: rate.NewLimiter(rate.Limit(50), 300)},
)
c := &ProxyProviderController{
kubeclientset: kubeclientset,
proxyProviderClientset: proxyProviderClientset,
authentik: authentik,
proxyLister: proxyInformer.Lister(),
}
c.controller = baseController.NewController(
ctx,
workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder,
proxyInformer.Informer().HasSynced,
c.syncHandler,
)
logger.Info("Setting up event handlers")
proxyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.controller.Enqueue,
UpdateFunc: func(_, newObj interface{}) {
c.controller.Enqueue(newObj)
},
})
return c
}
func (c *ProxyProviderController) Run(ctx context.Context, workers int) error {
return c.controller.Run(ctx, workers)
}
func (c *ProxyProviderController) syncHandler(ctx context.Context, objectRef cache.ObjectName) error {
logger := klog.LoggerWithValues(klog.FromContext(ctx), "objectRef", objectRef)
pp, err := c.proxyLister.ProxyProviders(objectRef.Namespace).Get(objectRef.Name)
if err != nil {
if errors.IsNotFound(err) {
logger.V(4).Info("ProxyProvider no longer exists")
return nil
}
return err
}
logger.V(4).Info("sync ProxyProvider", "name", pp.Name)
if !pp.ObjectMeta.DeletionTimestamp.IsZero() {
logger.Info("Reconciling deletion of ProxyProvider", "name", pp.Name)
return c.reconcileDelete(ctx, pp)
}
if pp.Status.PK == "" {
logger.Info("Reconciling creation of ProxyProvider", "name", pp.Name)
return c.reconcileCreate(ctx, pp)
}
// Check if all finalizers are present. If not, we add them. Same pattern as above, just needs a helper function to check for presence of a finalizer.
if !slices.Contains(pp.ObjectMeta.Finalizers, DeleteAuthentikProxyProviderFinalizer) {
logger.Info("Ensuring finalizers are present", "name", pp.Name)
return c.ensureFinalizers(ctx, pp)
}
logger.Info("Reconciling update of ProxyProvider", "name", pp.Name)
return c.reconcileUpdate(ctx, pp)
}
func (c *ProxyProviderController) ensureFinalizers(ctx context.Context, pp *v1alpha1.ProxyProvider) error {
pp.ObjectMeta.Finalizers = append(pp.ObjectMeta.Finalizers, DeleteAuthentikProxyProviderFinalizer)
return c.updateProxyProvider(ctx, pp)
}
func (c *ProxyProviderController) reconcileDelete(ctx context.Context, pp *v1alpha1.ProxyProvider) error {
pk, err := strconv.ParseInt(pp.Status.PK, 10, 32)
if err != nil {
return fmt.Errorf("error parsing PK: %v", err)
}
err = c.reconcileOutpost(ctx, pp.Spec.Outpost, int32(pk), ReconcileOutpostModeRemove)
if err != nil {
return fmt.Errorf("error when calling `reconcileOutpost`: %w", err)
}
// Delete ProxyProvider
r, err := c.authentik.ProvidersApi.ProvidersProxyDestroy(ctx, int32(pk)).Execute()
if err != nil {
// This handles an edge-case, where when the ProxyProvider on Authentik has already been deleted, but the finalizer is still present. We just remove the finalizer and return.
if r != nil && r.StatusCode != http.StatusNotFound {
return fmt.Errorf("error when calling `ProvidersAPI.ProvidersProxyDestroy`: %w with response %v", err, r)
}
}
pp.ObjectMeta.Finalizers = slices.Delete(pp.ObjectMeta.Finalizers, slices.Index(pp.ObjectMeta.Finalizers, DeleteAuthentikProxyProviderFinalizer), 1)
return c.updateProxyProvider(ctx, pp)
}
func (c *ProxyProviderController) reconcileUpdate(ctx context.Context, pp *v1alpha1.ProxyProvider) error {
// We retrieve the existing PP from the API by slug.
pk, err := strconv.ParseInt(pp.Status.PK, 10, 32)
if err != nil {
return fmt.Errorf("error parsing PK: %v", err)
}
_, r, err := c.authentik.ProvidersApi.ProvidersAllRetrieve(ctx, int32(pk)).Execute()
if err != nil {
if r != nil && r.StatusCode == http.StatusNotFound {
// This handles an edge-case, where when the PorxyProvider on Authentik has been deleted, e.g. by mistake. We just remove the PK and return.
// During the next reconciliation, the ProxyProvider will be re-created.
pp.Status.PK = ""
return c.updateProxyProviderStatus(ctx, pp)
}
return fmt.Errorf("error retrieving existing ProxyProvider: %v with response %v", err, r)
}
proxyProviderRequest := &authentikapi.PatchedProxyProviderRequest{
Name: &pp.Spec.Name,
AuthorizationFlow: &pp.Spec.AuthorizationFlow,
InvalidationFlow: &pp.Spec.InvalidationFlow,
ExternalHost: &pp.Spec.ExternalHost,
Mode: authentikapi.PROXYMODE_FORWARD_SINGLE.Ptr(),
}
resp, r, err := c.authentik.ProvidersApi.ProvidersProxyPartialUpdate(ctx, int32(pk)).PatchedProxyProviderRequest(*proxyProviderRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `ProvidersAPI.ProvidersProxyPartialUpdate`: %w with response %v", err, r)
}
pp.Status.PK = strconv.Itoa(int(resp.Pk))
err = c.reconcileOutpost(ctx, pp.Spec.Outpost, int32(pk), ReconcileOutpostModeAdd)
if err != nil {
return fmt.Errorf("error when calling `reconcileOutpost`: %w", err)
}
return c.updateProxyProviderStatus(ctx, pp)
}
func (c *ProxyProviderController) reconcileCreate(ctx context.Context, pp *v1alpha1.ProxyProvider) error {
proxyProviderRequest := &authentikapi.ProxyProviderRequest{
Name: pp.Spec.Name,
AuthorizationFlow: pp.Spec.AuthorizationFlow,
InvalidationFlow: pp.Spec.InvalidationFlow,
ExternalHost: pp.Spec.ExternalHost,
Mode: authentikapi.PROXYMODE_FORWARD_SINGLE.Ptr(),
}
resp, r, err := c.authentik.ProvidersApi.ProvidersProxyCreate(ctx).ProxyProviderRequest(*proxyProviderRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `ProvidersAPI.ProvidersProxyCreate`: %w with response %v", err, r)
}
err = c.reconcileOutpost(ctx, pp.Spec.Outpost, resp.Pk, ReconcileOutpostModeAdd)
if err != nil {
return fmt.Errorf("error when calling `reconcileOutpost`: %w", err)
}
pp.Status.PK = strconv.Itoa(int(resp.Pk))
return c.updateProxyProviderStatus(ctx, pp)
}
func (c *ProxyProviderController) updateProxyProviderStatus(ctx context.Context, pp *v1alpha1.ProxyProvider) error {
ppCopy := pp.DeepCopy()
_, err := c.proxyProviderClientset.ProxyproviderV1alpha1().ProxyProviders(ppCopy.Namespace).UpdateStatus(ctx, ppCopy, metav1.UpdateOptions{FieldManager: FieldManager})
return err
}
// Update metadata, spec, etc. of the ProxyProvider object.
func (c *ProxyProviderController) updateProxyProvider(ctx context.Context, pp *v1alpha1.ProxyProvider) error {
ppCopy := pp.DeepCopy()
_, err := c.proxyProviderClientset.ProxyproviderV1alpha1().ProxyProviders(ppCopy.Namespace).Update(ctx, ppCopy, metav1.UpdateOptions{FieldManager: FieldManager})
if err != nil {
return fmt.Errorf("error updating ProxyProvider metadata: %v", err)
}
return nil
}
type ReconcileOutpostMode string
const (
ReconcileOutpostModeAdd ReconcileOutpostMode = "add"
ReconcileOutpostModeRemove ReconcileOutpostMode = "remove"
)
func (c *ProxyProviderController) reconcileOutpost(ctx context.Context, outpostId string, providerPk int32, mode ReconcileOutpostMode) error {
logger := klog.LoggerWithValues(klog.FromContext(ctx), "outpostId", outpostId, "providerPk", providerPk, "mode", mode)
outpost, r, err := c.authentik.OutpostsApi.OutpostsInstancesRetrieve(ctx, outpostId).Execute()
if err != nil {
return fmt.Errorf("error when calling `OutpostsAPI.OutpostsInstancesRetrieve`: %w with response %v", err, r)
}
updated := false
switch mode {
case ReconcileOutpostModeAdd:
if !slices.Contains(outpost.Providers, providerPk) {
outpost.Providers = append(outpost.Providers, providerPk)
updated = true
} else {
logger.V(4).Info("Provider already in outpost")
}
case ReconcileOutpostModeRemove:
if slices.Contains(outpost.Providers, providerPk) {
outpost.Providers = slices.Delete(outpost.Providers, slices.Index(outpost.Providers, providerPk), 1)
updated = true
}
default:
return fmt.Errorf("invalid mode: %s", mode)
}
if !updated {
return nil
}
outpostPartialUpdateRequest := &authentikapi.PatchedOutpostRequest{
Providers: outpost.Providers,
}
_, r, err = c.authentik.OutpostsApi.OutpostsInstancesPartialUpdate(ctx, outpostId).PatchedOutpostRequest(*outpostPartialUpdateRequest).Execute()
if err != nil {
return fmt.Errorf("error when calling `OutpostsAPI.OutpostsInstancesPartialUpdate`: %w with response %v", err, r)
}
return nil
}
@@ -0,0 +1,547 @@
// AI generated tests and not yet reviewed.
package proxyprovider
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"slices"
"strings"
"testing"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
operatorfake "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/fake"
operatorinformers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions"
authentikapi "goauthentik.io/api/v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"
)
const testOutpostID = "550e8400-e29b-41d4-a716-446655440000"
func TestController_syncHandler_create(t *testing.T) {
const wantPK = 42
var outpostPartialUpdateCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
proxyCreate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusCreated, map[string]any{"pk": wantPK})
},
outpostRetrieve: outpostRetrieveHandler(t, nil),
outpostPartialUpdate: func(w http.ResponseWriter, r *http.Request) {
outpostPartialUpdateCalled = true
var body struct {
Providers []int32 `json:"providers"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatalf("decode outpost patch body: %v", err)
}
if !slices.Contains(body.Providers, wantPK) {
t.Fatalf("patched providers = %v, want to contain %d", body.Providers, wantPK)
}
writeJSON(t, w, http.StatusOK, map[string]any{"pk": testOutpostID, "providers": body.Providers})
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, testProxyProvider(), server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "test-pp"})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if !outpostPartialUpdateCalled {
t.Fatal("expected Authentik outpost partial update call")
}
got := getProxyProvider(t, ctrl, "default", "test-pp")
if got.Status.PK != "42" {
t.Fatalf("status.pk = %q, want 42", got.Status.PK)
}
}
func TestController_syncHandler_create_providerAlreadyInOutpost(t *testing.T) {
const wantPK = 42
var outpostPartialUpdateCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
proxyCreate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusCreated, map[string]any{"pk": wantPK})
},
outpostRetrieve: outpostRetrieveHandler(t, []int32{wantPK}),
outpostPartialUpdate: func(w http.ResponseWriter, _ *http.Request) {
outpostPartialUpdateCalled = true
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, testProxyProvider(), server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "test-pp"})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if outpostPartialUpdateCalled {
t.Fatal("did not expect Authentik outpost partial update when provider is already present")
}
got := getProxyProvider(t, ctrl, "default", "test-pp")
if got.Status.PK != "42" {
t.Fatalf("status.pk = %q, want 42", got.Status.PK)
}
}
func TestController_syncHandler_ensureFinalizers(t *testing.T) {
pp := testProxyProvider()
pp.Status.PK = "42"
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getProxyProvider(t, ctrl, pp.Namespace, pp.Name)
if !slices.Contains(got.Finalizers, DeleteAuthentikProxyProviderFinalizer) {
t.Fatalf("finalizers = %v, want %q", got.Finalizers, DeleteAuthentikProxyProviderFinalizer)
}
}
func TestController_syncHandler_update(t *testing.T) {
pp := testProxyProvider()
pp.Status.PK = "42"
pp.Finalizers = []string{DeleteAuthentikProxyProviderFinalizer}
var outpostPartialUpdateCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
allRetrieve: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{"pk": 42})
},
proxyPartialUpdate: func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{"pk": 42})
},
outpostRetrieve: outpostRetrieveHandler(t, nil),
outpostPartialUpdate: func(w http.ResponseWriter, r *http.Request) {
outpostPartialUpdateCalled = true
var body struct {
Providers []int32 `json:"providers"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatalf("decode outpost patch body: %v", err)
}
if !slices.Contains(body.Providers, 42) {
t.Fatalf("patched providers = %v, want to contain 42", body.Providers)
}
writeJSON(t, w, http.StatusOK, map[string]any{"pk": testOutpostID, "providers": body.Providers})
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if !outpostPartialUpdateCalled {
t.Fatal("expected Authentik outpost partial update call")
}
got := getProxyProvider(t, ctrl, pp.Namespace, pp.Name)
if got.Status.PK != "42" {
t.Fatalf("status.pk = %q, want 42", got.Status.PK)
}
}
func TestController_syncHandler_update_providerNotFound(t *testing.T) {
pp := testProxyProvider()
pp.Status.PK = "42"
pp.Finalizers = []string{DeleteAuthentikProxyProviderFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
allRetrieve: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getProxyProvider(t, ctrl, pp.Namespace, pp.Name)
if got.Status.PK != "" {
t.Fatalf("status.pk = %q, want empty after provider not found", got.Status.PK)
}
}
func TestController_syncHandler_delete(t *testing.T) {
const wantPK int32 = 42
now := metav1.Now()
pp := testProxyProvider()
pp.Status.PK = "42"
pp.DeletionTimestamp = &now
pp.Finalizers = []string{DeleteAuthentikProxyProviderFinalizer}
var outpostPartialUpdateCalled, destroyCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
outpostRetrieve: outpostRetrieveHandler(t, []int32{wantPK}),
outpostPartialUpdate: func(w http.ResponseWriter, r *http.Request) {
outpostPartialUpdateCalled = true
var body struct {
Providers []int32 `json:"providers"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatalf("decode outpost patch body: %v", err)
}
if slices.Contains(body.Providers, wantPK) {
t.Fatalf("patched providers = %v, want provider %d removed", body.Providers, wantPK)
}
writeJSON(t, w, http.StatusOK, map[string]any{"pk": testOutpostID, "providers": body.Providers})
},
proxyDestroy: func(w http.ResponseWriter, r *http.Request) {
destroyCalled = true
if r.Method != http.MethodDelete {
t.Errorf("destroy method = %s, want DELETE", r.Method)
}
w.WriteHeader(http.StatusNoContent)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if !outpostPartialUpdateCalled {
t.Fatal("expected Authentik outpost partial update call")
}
if !destroyCalled {
t.Fatal("expected Authentik destroy call")
}
got := getProxyProvider(t, ctrl, pp.Namespace, pp.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikProxyProviderFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed", got.Finalizers)
}
}
func TestController_syncHandler_delete_providerNotInOutpost(t *testing.T) {
now := metav1.Now()
pp := testProxyProvider()
pp.Status.PK = "42"
pp.DeletionTimestamp = &now
pp.Finalizers = []string{DeleteAuthentikProxyProviderFinalizer}
var outpostPartialUpdateCalled, destroyCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{
outpostRetrieve: outpostRetrieveHandler(t, nil),
outpostPartialUpdate: func(w http.ResponseWriter, _ *http.Request) {
outpostPartialUpdateCalled = true
},
proxyDestroy: func(w http.ResponseWriter, _ *http.Request) {
destroyCalled = true
w.WriteHeader(http.StatusNoContent)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
if outpostPartialUpdateCalled {
t.Fatal("did not expect Authentik outpost partial update when provider is not in outpost")
}
if !destroyCalled {
t.Fatal("expected Authentik destroy call")
}
got := getProxyProvider(t, ctrl, pp.Namespace, pp.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikProxyProviderFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed", got.Finalizers)
}
}
func TestController_syncHandler_delete_providerAlreadyGone(t *testing.T) {
const wantPK int32 = 42
now := metav1.Now()
pp := testProxyProvider()
pp.Status.PK = "42"
pp.DeletionTimestamp = &now
pp.Finalizers = []string{DeleteAuthentikProxyProviderFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{
outpostRetrieve: outpostRetrieveHandler(t, []int32{wantPK}),
outpostPartialUpdate: func(w http.ResponseWriter, r *http.Request) {
var body struct {
Providers []int32 `json:"providers"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Fatalf("decode outpost patch body: %v", err)
}
writeJSON(t, w, http.StatusOK, map[string]any{"pk": testOutpostID, "providers": body.Providers})
},
proxyDestroy: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil)
},
})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err != nil {
t.Fatalf("syncHandler() error = %v", err)
}
got := getProxyProvider(t, ctrl, pp.Namespace, pp.Name)
if slices.Contains(got.Finalizers, DeleteAuthentikProxyProviderFinalizer) {
t.Fatalf("finalizers = %v, want finalizer removed after 404", got.Finalizers)
}
}
func TestController_syncHandler_notFound(t *testing.T) {
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, nil, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: "default", Name: "missing"})
if err != nil {
t.Fatalf("syncHandler() error = %v, want nil for missing object", err)
}
}
func TestController_syncHandler_invalidPK(t *testing.T) {
pp := testProxyProvider()
pp.Status.PK = "not-a-number"
pp.Finalizers = []string{DeleteAuthentikProxyProviderFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{})
t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, pp, server.URL)
t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: pp.Namespace, Name: pp.Name})
if err == nil {
t.Fatal("syncHandler() error = nil, want parse error")
}
if !strings.Contains(err.Error(), "error parsing PK") {
t.Fatalf("syncHandler() error = %v, want PK parse error", err)
}
}
// --- test helpers ---
func testProxyProvider() *v1alpha1.ProxyProvider {
return &v1alpha1.ProxyProvider{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: "ProxyProvider",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-pp",
Namespace: "default",
},
Spec: v1alpha1.ProxyProviderSpec{
Name: "my-app",
AuthorizationFlow: "flow-auth",
InvalidationFlow: "flow-invalidate",
ExternalHost: "https://app.example.com",
Outpost: testOutpostID,
},
}
}
func newTestController(t *testing.T, pp *v1alpha1.ProxyProvider, authentikURL string) (*ProxyProviderController, context.Context, context.CancelFunc) {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
ctrl, _, stop := newTestControllerWithContext(t, ctx, pp, authentikURL)
return ctrl, ctx, func() {
cancel()
stop()
}
}
func newTestControllerWithContext(t *testing.T, ctx context.Context, pp *v1alpha1.ProxyProvider, authentikURL string) (*ProxyProviderController, context.Context, func()) {
t.Helper()
authentikClient := newAuthentikAPIClientForTest(t, authentikURL)
var objects []runtime.Object
if pp != nil {
objects = append(objects, pp)
}
proxyClient := operatorfake.NewSimpleClientset(objects...)
informerFactory := operatorinformers.NewSharedInformerFactory(proxyClient, 0)
proxyInformer := informerFactory.Proxyprovider().V1alpha1().ProxyProviders()
ctrl := NewController(ctx, fake.NewClientset(), proxyClient, authentikClient, proxyInformer)
informerFactory.Start(ctx.Done())
for informerType, synced := range informerFactory.WaitForCacheSync(ctx.Done()) {
if !synced {
t.Fatalf("informer %v failed to sync", informerType)
}
}
return ctrl, ctx, func() {}
}
func newAuthentikAPIClientForTest(t *testing.T, serverURL string) *authentikapi.APIClient {
t.Helper()
u, err := url.Parse(serverURL)
if err != nil {
t.Fatalf("parse server URL: %v", err)
}
cfg := authentikapi.NewConfiguration()
cfg.Scheme = u.Scheme
cfg.Host = u.Host
return authentikapi.NewAPIClient(cfg)
}
type authentikTestHandlers struct {
proxyCreate http.HandlerFunc
proxyDestroy http.HandlerFunc
proxyPartialUpdate http.HandlerFunc
allRetrieve http.HandlerFunc
outpostRetrieve http.HandlerFunc
outpostPartialUpdate http.HandlerFunc
}
func outpostRetrieveHandler(t *testing.T, providers []int32) http.HandlerFunc {
t.Helper()
return func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, http.StatusOK, map[string]any{
"pk": testOutpostID,
"providers": providers,
})
}
}
func newAuthentikTestServer(t *testing.T, handlers authentikTestHandlers) *httptest.Server {
t.Helper()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
switch {
case path == "/api/v3/providers/proxy/" && r.Method == http.MethodPost:
if handlers.proxyCreate != nil {
handlers.proxyCreate(w, r)
return
}
http.NotFound(w, r)
case strings.HasPrefix(path, "/api/v3/providers/proxy/") && strings.HasSuffix(path, "/"):
idPath := strings.TrimPrefix(path, "/api/v3/providers/proxy/")
if idPath == "" {
http.NotFound(w, r)
return
}
switch r.Method {
case http.MethodDelete:
if handlers.proxyDestroy != nil {
handlers.proxyDestroy(w, r)
return
}
http.NotFound(w, r)
case http.MethodPatch:
if handlers.proxyPartialUpdate != nil {
handlers.proxyPartialUpdate(w, r)
return
}
http.NotFound(w, r)
default:
http.Error(w, "unexpected method on proxy instance", http.StatusMethodNotAllowed)
}
case strings.HasPrefix(path, "/api/v3/providers/all/") && strings.HasSuffix(path, "/"):
if r.Method == http.MethodGet && handlers.allRetrieve != nil {
handlers.allRetrieve(w, r)
return
}
http.NotFound(w, r)
case strings.HasPrefix(path, "/api/v3/outposts/instances/") && strings.HasSuffix(path, "/"):
idPath := strings.TrimPrefix(path, "/api/v3/outposts/instances/")
idPath = strings.TrimSuffix(idPath, "/")
if idPath == "" || strings.Contains(idPath, "/") {
http.NotFound(w, r)
return
}
switch r.Method {
case http.MethodGet:
if handlers.outpostRetrieve != nil {
handlers.outpostRetrieve(w, r)
return
}
http.NotFound(w, r)
case http.MethodPatch:
if handlers.outpostPartialUpdate != nil {
handlers.outpostPartialUpdate(w, r)
return
}
http.NotFound(w, r)
default:
http.Error(w, "unexpected method on outpost instance", http.StatusMethodNotAllowed)
}
default:
http.NotFound(w, r)
}
})
return httptest.NewServer(handler)
}
func writeJSON(t *testing.T, w http.ResponseWriter, status int, body any) {
t.Helper()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if err := json.NewEncoder(w).Encode(body); err != nil {
t.Fatalf("write JSON response: %v", err)
}
}
func getProxyProvider(t *testing.T, ctrl *ProxyProviderController, namespace, name string) *v1alpha1.ProxyProvider {
t.Helper()
got, err := ctrl.proxyProviderClientset.ProxyproviderV1alpha1().ProxyProviders(namespace).Get(
context.Background(), name, metav1.GetOptions{},
)
if err != nil {
t.Fatalf("get ProxyProvider: %v", err)
}
return got
}
@@ -19,83 +19,37 @@ limitations under the License.
package v1alpha1 package v1alpha1
import ( import (
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1"
internal "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/internal"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types" types "k8s.io/apimachinery/pkg/types"
managedfields "k8s.io/apimachinery/pkg/util/managedfields"
v1 "k8s.io/client-go/applyconfigurations/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1"
) )
// FooApplyConfiguration represents a declarative configuration of the Foo type for use // ApplicationApplyConfiguration represents a declarative configuration of the Application type for use
// with apply. // with apply.
// type ApplicationApplyConfiguration struct {
// Foo is a specification for a Foo resource v1.TypeMetaApplyConfiguration `json:""`
type FooApplyConfiguration struct {
v1.TypeMetaApplyConfiguration `json:",inline"`
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
Spec *FooSpecApplyConfiguration `json:"spec,omitempty"` Spec *ApplicationSpecApplyConfiguration `json:"spec,omitempty"`
Status *FooStatusApplyConfiguration `json:"status,omitempty"` Status *ApplicationStatusApplyConfiguration `json:"status,omitempty"`
} }
// Foo constructs a declarative configuration of the Foo type for use with // Application constructs a declarative configuration of the Application type for use with
// apply. // apply.
func Foo(name, namespace string) *FooApplyConfiguration { func Application(name, namespace string) *ApplicationApplyConfiguration {
b := &FooApplyConfiguration{} b := &ApplicationApplyConfiguration{}
b.WithName(name) b.WithName(name)
b.WithNamespace(namespace) b.WithNamespace(namespace)
b.WithKind("Foo") b.WithKind("Application")
b.WithAPIVersion("samplecontroller.k8s.io/v1alpha1") b.WithAPIVersion("application.t000-n.de/v1alpha1")
return b return b
} }
// ExtractFooFrom extracts the applied configuration owned by fieldManager from func (b ApplicationApplyConfiguration) IsApplyConfiguration() {}
// foo for the specified subresource. Pass an empty string for subresource to extract
// the main resource. Common subresources include "status", "scale", etc.
// foo must be a unmodified Foo API object that was retrieved from the Kubernetes API.
// ExtractFooFrom provides a way to perform a extract/modify-in-place/apply workflow.
// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously
// applied if another fieldManager has updated or force applied any of the previously applied fields.
func ExtractFooFrom(foo *samplecontrollerv1alpha1.Foo, fieldManager string, subresource string) (*FooApplyConfiguration, error) {
b := &FooApplyConfiguration{}
err := managedfields.ExtractInto(foo, internal.Parser().Type("io.k8s.sample-controller.pkg.apis.samplecontroller.v1alpha1.Foo"), fieldManager, b, subresource)
if err != nil {
return nil, err
}
b.WithName(foo.Name)
b.WithNamespace(foo.Namespace)
b.WithKind("Foo")
b.WithAPIVersion("samplecontroller.k8s.io/v1alpha1")
return b, nil
}
// ExtractFoo extracts the applied configuration owned by fieldManager from
// foo. If no managedFields are found in foo for fieldManager, a
// FooApplyConfiguration is returned with only the Name, Namespace (if applicable),
// APIVersion and Kind populated. It is possible that no managed fields were found for because other
// field managers have taken ownership of all the fields previously owned by fieldManager, or because
// the fieldManager never owned fields any fields.
// foo must be a unmodified Foo API object that was retrieved from the Kubernetes API.
// ExtractFoo provides a way to perform a extract/modify-in-place/apply workflow.
// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously
// applied if another fieldManager has updated or force applied any of the previously applied fields.
func ExtractFoo(foo *samplecontrollerv1alpha1.Foo, fieldManager string) (*FooApplyConfiguration, error) {
return ExtractFooFrom(foo, fieldManager, "")
}
// ExtractFooStatus extracts the applied configuration owned by fieldManager from
// foo for the status subresource.
func ExtractFooStatus(foo *samplecontrollerv1alpha1.Foo, fieldManager string) (*FooApplyConfiguration, error) {
return ExtractFooFrom(foo, fieldManager, "status")
}
func (b FooApplyConfiguration) IsApplyConfiguration() {}
// WithKind sets the Kind field in the declarative configuration to the given value // WithKind sets the Kind field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Kind field is set to the value of the last call. // If called multiple times, the Kind field is set to the value of the last call.
func (b *FooApplyConfiguration) WithKind(value string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithKind(value string) *ApplicationApplyConfiguration {
b.TypeMetaApplyConfiguration.Kind = &value b.TypeMetaApplyConfiguration.Kind = &value
return b return b
} }
@@ -103,7 +57,7 @@ func (b *FooApplyConfiguration) WithKind(value string) *FooApplyConfiguration {
// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value // WithAPIVersion sets the APIVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the APIVersion field is set to the value of the last call. // If called multiple times, the APIVersion field is set to the value of the last call.
func (b *FooApplyConfiguration) WithAPIVersion(value string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithAPIVersion(value string) *ApplicationApplyConfiguration {
b.TypeMetaApplyConfiguration.APIVersion = &value b.TypeMetaApplyConfiguration.APIVersion = &value
return b return b
} }
@@ -111,7 +65,7 @@ func (b *FooApplyConfiguration) WithAPIVersion(value string) *FooApplyConfigurat
// WithName sets the Name field in the declarative configuration to the given value // WithName sets the Name field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Name field is set to the value of the last call. // If called multiple times, the Name field is set to the value of the last call.
func (b *FooApplyConfiguration) WithName(value string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithName(value string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Name = &value b.ObjectMetaApplyConfiguration.Name = &value
return b return b
@@ -120,7 +74,7 @@ func (b *FooApplyConfiguration) WithName(value string) *FooApplyConfiguration {
// WithGenerateName sets the GenerateName field in the declarative configuration to the given value // WithGenerateName sets the GenerateName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the GenerateName field is set to the value of the last call. // If called multiple times, the GenerateName field is set to the value of the last call.
func (b *FooApplyConfiguration) WithGenerateName(value string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithGenerateName(value string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.GenerateName = &value b.ObjectMetaApplyConfiguration.GenerateName = &value
return b return b
@@ -129,7 +83,7 @@ func (b *FooApplyConfiguration) WithGenerateName(value string) *FooApplyConfigur
// WithNamespace sets the Namespace field in the declarative configuration to the given value // WithNamespace sets the Namespace field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Namespace field is set to the value of the last call. // If called multiple times, the Namespace field is set to the value of the last call.
func (b *FooApplyConfiguration) WithNamespace(value string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithNamespace(value string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Namespace = &value b.ObjectMetaApplyConfiguration.Namespace = &value
return b return b
@@ -138,7 +92,7 @@ func (b *FooApplyConfiguration) WithNamespace(value string) *FooApplyConfigurati
// WithUID sets the UID field in the declarative configuration to the given value // WithUID sets the UID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the UID field is set to the value of the last call. // If called multiple times, the UID field is set to the value of the last call.
func (b *FooApplyConfiguration) WithUID(value types.UID) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithUID(value types.UID) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.UID = &value b.ObjectMetaApplyConfiguration.UID = &value
return b return b
@@ -147,7 +101,7 @@ func (b *FooApplyConfiguration) WithUID(value types.UID) *FooApplyConfiguration
// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value // WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ResourceVersion field is set to the value of the last call. // If called multiple times, the ResourceVersion field is set to the value of the last call.
func (b *FooApplyConfiguration) WithResourceVersion(value string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithResourceVersion(value string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.ResourceVersion = &value b.ObjectMetaApplyConfiguration.ResourceVersion = &value
return b return b
@@ -156,7 +110,7 @@ func (b *FooApplyConfiguration) WithResourceVersion(value string) *FooApplyConfi
// WithGeneration sets the Generation field in the declarative configuration to the given value // WithGeneration sets the Generation field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Generation field is set to the value of the last call. // If called multiple times, the Generation field is set to the value of the last call.
func (b *FooApplyConfiguration) WithGeneration(value int64) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithGeneration(value int64) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Generation = &value b.ObjectMetaApplyConfiguration.Generation = &value
return b return b
@@ -165,7 +119,7 @@ func (b *FooApplyConfiguration) WithGeneration(value int64) *FooApplyConfigurati
// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value // WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the CreationTimestamp field is set to the value of the last call. // If called multiple times, the CreationTimestamp field is set to the value of the last call.
func (b *FooApplyConfiguration) WithCreationTimestamp(value metav1.Time) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.CreationTimestamp = &value b.ObjectMetaApplyConfiguration.CreationTimestamp = &value
return b return b
@@ -174,7 +128,7 @@ func (b *FooApplyConfiguration) WithCreationTimestamp(value metav1.Time) *FooApp
// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value // WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionTimestamp field is set to the value of the last call. // If called multiple times, the DeletionTimestamp field is set to the value of the last call.
func (b *FooApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value
return b return b
@@ -183,7 +137,7 @@ func (b *FooApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *FooApp
// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value // WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. // If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call.
func (b *FooApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value
return b return b
@@ -193,7 +147,7 @@ func (b *FooApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *Foo
// and returns the receiver, so that objects can be build by chaining "With" function invocations. // and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Labels field, // If called multiple times, the entries provided by each call will be put on the Labels field,
// overwriting an existing map entries in Labels field with the same key. // overwriting an existing map entries in Labels field with the same key.
func (b *FooApplyConfiguration) WithLabels(entries map[string]string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithLabels(entries map[string]string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries))
@@ -208,7 +162,7 @@ func (b *FooApplyConfiguration) WithLabels(entries map[string]string) *FooApplyC
// and returns the receiver, so that objects can be build by chaining "With" function invocations. // and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Annotations field, // If called multiple times, the entries provided by each call will be put on the Annotations field,
// overwriting an existing map entries in Annotations field with the same key. // overwriting an existing map entries in Annotations field with the same key.
func (b *FooApplyConfiguration) WithAnnotations(entries map[string]string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithAnnotations(entries map[string]string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries))
@@ -222,7 +176,7 @@ func (b *FooApplyConfiguration) WithAnnotations(entries map[string]string) *FooA
// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration // WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations. // and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the OwnerReferences field. // If called multiple times, values provided by each call will be appended to the OwnerReferences field.
func (b *FooApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
for i := range values { for i := range values {
if values[i] == nil { if values[i] == nil {
@@ -236,7 +190,7 @@ func (b *FooApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReference
// WithFinalizers adds the given value to the Finalizers field in the declarative configuration // WithFinalizers adds the given value to the Finalizers field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations. // and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the Finalizers field. // If called multiple times, values provided by each call will be appended to the Finalizers field.
func (b *FooApplyConfiguration) WithFinalizers(values ...string) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithFinalizers(values ...string) *ApplicationApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
for i := range values { for i := range values {
b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i])
@@ -244,7 +198,7 @@ func (b *FooApplyConfiguration) WithFinalizers(values ...string) *FooApplyConfig
return b return b
} }
func (b *FooApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { func (b *ApplicationApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
if b.ObjectMetaApplyConfiguration == nil { if b.ObjectMetaApplyConfiguration == nil {
b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{}
} }
@@ -253,7 +207,7 @@ func (b *FooApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
// WithSpec sets the Spec field in the declarative configuration to the given value // WithSpec sets the Spec field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Spec field is set to the value of the last call. // If called multiple times, the Spec field is set to the value of the last call.
func (b *FooApplyConfiguration) WithSpec(value *FooSpecApplyConfiguration) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithSpec(value *ApplicationSpecApplyConfiguration) *ApplicationApplyConfiguration {
b.Spec = value b.Spec = value
return b return b
} }
@@ -261,29 +215,29 @@ func (b *FooApplyConfiguration) WithSpec(value *FooSpecApplyConfiguration) *FooA
// WithStatus sets the Status field in the declarative configuration to the given value // WithStatus sets the Status field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Status field is set to the value of the last call. // If called multiple times, the Status field is set to the value of the last call.
func (b *FooApplyConfiguration) WithStatus(value *FooStatusApplyConfiguration) *FooApplyConfiguration { func (b *ApplicationApplyConfiguration) WithStatus(value *ApplicationStatusApplyConfiguration) *ApplicationApplyConfiguration {
b.Status = value b.Status = value
return b return b
} }
// GetKind retrieves the value of the Kind field in the declarative configuration. // GetKind retrieves the value of the Kind field in the declarative configuration.
func (b *FooApplyConfiguration) GetKind() *string { func (b *ApplicationApplyConfiguration) GetKind() *string {
return b.TypeMetaApplyConfiguration.Kind return b.TypeMetaApplyConfiguration.Kind
} }
// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. // GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration.
func (b *FooApplyConfiguration) GetAPIVersion() *string { func (b *ApplicationApplyConfiguration) GetAPIVersion() *string {
return b.TypeMetaApplyConfiguration.APIVersion return b.TypeMetaApplyConfiguration.APIVersion
} }
// GetName retrieves the value of the Name field in the declarative configuration. // GetName retrieves the value of the Name field in the declarative configuration.
func (b *FooApplyConfiguration) GetName() *string { func (b *ApplicationApplyConfiguration) GetName() *string {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Name return b.ObjectMetaApplyConfiguration.Name
} }
// GetNamespace retrieves the value of the Namespace field in the declarative configuration. // GetNamespace retrieves the value of the Namespace field in the declarative configuration.
func (b *FooApplyConfiguration) GetNamespace() *string { func (b *ApplicationApplyConfiguration) GetNamespace() *string {
b.ensureObjectMetaApplyConfigurationExists() b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Namespace return b.ObjectMetaApplyConfiguration.Namespace
} }
@@ -0,0 +1,57 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
// ApplicationSpecApplyConfiguration represents a declarative configuration of the ApplicationSpec type for use
// with apply.
type ApplicationSpecApplyConfiguration struct {
Name *string `json:"name,omitempty"`
Slug *string `json:"slug,omitempty"`
Provider *int32 `json:"provider,omitempty"`
}
// ApplicationSpecApplyConfiguration constructs a declarative configuration of the ApplicationSpec type for use with
// apply.
func ApplicationSpec() *ApplicationSpecApplyConfiguration {
return &ApplicationSpecApplyConfiguration{}
}
// WithName sets the Name field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Name field is set to the value of the last call.
func (b *ApplicationSpecApplyConfiguration) WithName(value string) *ApplicationSpecApplyConfiguration {
b.Name = &value
return b
}
// WithSlug sets the Slug field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Slug field is set to the value of the last call.
func (b *ApplicationSpecApplyConfiguration) WithSlug(value string) *ApplicationSpecApplyConfiguration {
b.Slug = &value
return b
}
// WithProvider sets the Provider field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Provider field is set to the value of the last call.
func (b *ApplicationSpecApplyConfiguration) WithProvider(value int32) *ApplicationSpecApplyConfiguration {
b.Provider = &value
return b
}
@@ -18,24 +18,22 @@ limitations under the License.
package v1alpha1 package v1alpha1
// FooStatusApplyConfiguration represents a declarative configuration of the FooStatus type for use // ApplicationStatusApplyConfiguration represents a declarative configuration of the ApplicationStatus type for use
// with apply. // with apply.
// type ApplicationStatusApplyConfiguration struct {
// FooStatus is the status for a Foo resource PK *string `json:"pk,omitempty"`
type FooStatusApplyConfiguration struct {
AvailableReplicas *int32 `json:"availableReplicas,omitempty"`
} }
// FooStatusApplyConfiguration constructs a declarative configuration of the FooStatus type for use with // ApplicationStatusApplyConfiguration constructs a declarative configuration of the ApplicationStatus type for use with
// apply. // apply.
func FooStatus() *FooStatusApplyConfiguration { func ApplicationStatus() *ApplicationStatusApplyConfiguration {
return &FooStatusApplyConfiguration{} return &ApplicationStatusApplyConfiguration{}
} }
// WithAvailableReplicas sets the AvailableReplicas field in the declarative configuration to the given value // WithPK sets the PK field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations. // and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the AvailableReplicas field is set to the value of the last call. // If called multiple times, the PK field is set to the value of the last call.
func (b *FooStatusApplyConfiguration) WithAvailableReplicas(value int32) *FooStatusApplyConfiguration { func (b *ApplicationStatusApplyConfiguration) WithPK(value string) *ApplicationStatusApplyConfiguration {
b.AvailableReplicas = &value b.PK = &value
return b return b
} }
@@ -39,16 +39,6 @@ func Parser() *typed.Parser {
var parserOnce sync.Once var parserOnce sync.Once
var parser *typed.Parser var parser *typed.Parser
var schemaYAML = typed.YAMLObject(`types: var schemaYAML = typed.YAMLObject(`types:
- name: io.k8s.sample-controller.pkg.apis.samplecontroller.v1alpha1.Foo
scalar: untyped
list:
elementType:
namedType: __untyped_atomic_
elementRelationship: atomic
map:
elementType:
namedType: __untyped_deduced_
elementRelationship: separable
- name: __untyped_atomic_ - name: __untyped_atomic_
scalar: untyped scalar: untyped
list: list:
@@ -0,0 +1,243 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// PolicyBindingApplyConfiguration represents a declarative configuration of the PolicyBinding type for use
// with apply.
type PolicyBindingApplyConfiguration struct {
v1.TypeMetaApplyConfiguration `json:""`
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
Spec *PolicyBindingSpecApplyConfiguration `json:"spec,omitempty"`
Status *PolicyBindingStatusApplyConfiguration `json:"status,omitempty"`
}
// PolicyBinding constructs a declarative configuration of the PolicyBinding type for use with
// apply.
func PolicyBinding(name, namespace string) *PolicyBindingApplyConfiguration {
b := &PolicyBindingApplyConfiguration{}
b.WithName(name)
b.WithNamespace(namespace)
b.WithKind("PolicyBinding")
b.WithAPIVersion("policybinding.t000-n.de/v1alpha1")
return b
}
func (b PolicyBindingApplyConfiguration) IsApplyConfiguration() {}
// WithKind sets the Kind field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Kind field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithKind(value string) *PolicyBindingApplyConfiguration {
b.TypeMetaApplyConfiguration.Kind = &value
return b
}
// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the APIVersion field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithAPIVersion(value string) *PolicyBindingApplyConfiguration {
b.TypeMetaApplyConfiguration.APIVersion = &value
return b
}
// WithName sets the Name field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Name field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithName(value string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Name = &value
return b
}
// WithGenerateName sets the GenerateName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the GenerateName field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithGenerateName(value string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.GenerateName = &value
return b
}
// WithNamespace sets the Namespace field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Namespace field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithNamespace(value string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Namespace = &value
return b
}
// WithUID sets the UID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the UID field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithUID(value types.UID) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.UID = &value
return b
}
// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ResourceVersion field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithResourceVersion(value string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.ResourceVersion = &value
return b
}
// WithGeneration sets the Generation field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Generation field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithGeneration(value int64) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Generation = &value
return b
}
// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the CreationTimestamp field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithCreationTimestamp(value metav1.Time) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.CreationTimestamp = &value
return b
}
// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionTimestamp field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value
return b
}
// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value
return b
}
// WithLabels puts the entries into the Labels field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Labels field,
// overwriting an existing map entries in Labels field with the same key.
func (b *PolicyBindingApplyConfiguration) WithLabels(entries map[string]string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries))
}
for k, v := range entries {
b.ObjectMetaApplyConfiguration.Labels[k] = v
}
return b
}
// WithAnnotations puts the entries into the Annotations field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Annotations field,
// overwriting an existing map entries in Annotations field with the same key.
func (b *PolicyBindingApplyConfiguration) WithAnnotations(entries map[string]string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries))
}
for k, v := range entries {
b.ObjectMetaApplyConfiguration.Annotations[k] = v
}
return b
}
// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the OwnerReferences field.
func (b *PolicyBindingApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
for i := range values {
if values[i] == nil {
panic("nil value passed to WithOwnerReferences")
}
b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i])
}
return b
}
// WithFinalizers adds the given value to the Finalizers field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the Finalizers field.
func (b *PolicyBindingApplyConfiguration) WithFinalizers(values ...string) *PolicyBindingApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
for i := range values {
b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i])
}
return b
}
func (b *PolicyBindingApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
if b.ObjectMetaApplyConfiguration == nil {
b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{}
}
}
// WithSpec sets the Spec field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Spec field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithSpec(value *PolicyBindingSpecApplyConfiguration) *PolicyBindingApplyConfiguration {
b.Spec = value
return b
}
// WithStatus sets the Status field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Status field is set to the value of the last call.
func (b *PolicyBindingApplyConfiguration) WithStatus(value *PolicyBindingStatusApplyConfiguration) *PolicyBindingApplyConfiguration {
b.Status = value
return b
}
// GetKind retrieves the value of the Kind field in the declarative configuration.
func (b *PolicyBindingApplyConfiguration) GetKind() *string {
return b.TypeMetaApplyConfiguration.Kind
}
// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration.
func (b *PolicyBindingApplyConfiguration) GetAPIVersion() *string {
return b.TypeMetaApplyConfiguration.APIVersion
}
// GetName retrieves the value of the Name field in the declarative configuration.
func (b *PolicyBindingApplyConfiguration) GetName() *string {
b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Name
}
// GetNamespace retrieves the value of the Namespace field in the declarative configuration.
func (b *PolicyBindingApplyConfiguration) GetNamespace() *string {
b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Namespace
}
@@ -0,0 +1,75 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
// PolicyBindingSpecApplyConfiguration represents a declarative configuration of the PolicyBindingSpec type for use
// with apply.
type PolicyBindingSpecApplyConfiguration struct {
Policy *string `json:"policy,omitempty"`
Group *string `json:"group,omitempty"`
User *int32 `json:"user,omitempty"`
Target *string `json:"target,omitempty"`
Order *int32 `json:"order,omitempty"`
}
// PolicyBindingSpecApplyConfiguration constructs a declarative configuration of the PolicyBindingSpec type for use with
// apply.
func PolicyBindingSpec() *PolicyBindingSpecApplyConfiguration {
return &PolicyBindingSpecApplyConfiguration{}
}
// WithPolicy sets the Policy field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Policy field is set to the value of the last call.
func (b *PolicyBindingSpecApplyConfiguration) WithPolicy(value string) *PolicyBindingSpecApplyConfiguration {
b.Policy = &value
return b
}
// WithGroup sets the Group field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Group field is set to the value of the last call.
func (b *PolicyBindingSpecApplyConfiguration) WithGroup(value string) *PolicyBindingSpecApplyConfiguration {
b.Group = &value
return b
}
// WithUser sets the User field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the User field is set to the value of the last call.
func (b *PolicyBindingSpecApplyConfiguration) WithUser(value int32) *PolicyBindingSpecApplyConfiguration {
b.User = &value
return b
}
// WithTarget sets the Target field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Target field is set to the value of the last call.
func (b *PolicyBindingSpecApplyConfiguration) WithTarget(value string) *PolicyBindingSpecApplyConfiguration {
b.Target = &value
return b
}
// WithOrder sets the Order field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Order field is set to the value of the last call.
func (b *PolicyBindingSpecApplyConfiguration) WithOrder(value int32) *PolicyBindingSpecApplyConfiguration {
b.Order = &value
return b
}
@@ -0,0 +1,39 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
// PolicyBindingStatusApplyConfiguration represents a declarative configuration of the PolicyBindingStatus type for use
// with apply.
type PolicyBindingStatusApplyConfiguration struct {
PK *string `json:"pk,omitempty"`
}
// PolicyBindingStatusApplyConfiguration constructs a declarative configuration of the PolicyBindingStatus type for use with
// apply.
func PolicyBindingStatus() *PolicyBindingStatusApplyConfiguration {
return &PolicyBindingStatusApplyConfiguration{}
}
// WithPK sets the PK field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the PK field is set to the value of the last call.
func (b *PolicyBindingStatusApplyConfiguration) WithPK(value string) *PolicyBindingStatusApplyConfiguration {
b.PK = &value
return b
}
@@ -0,0 +1,243 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// ProxyProviderApplyConfiguration represents a declarative configuration of the ProxyProvider type for use
// with apply.
type ProxyProviderApplyConfiguration struct {
v1.TypeMetaApplyConfiguration `json:""`
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
Spec *ProxyProviderSpecApplyConfiguration `json:"spec,omitempty"`
Status *ProxyProviderStatusApplyConfiguration `json:"status,omitempty"`
}
// ProxyProvider constructs a declarative configuration of the ProxyProvider type for use with
// apply.
func ProxyProvider(name, namespace string) *ProxyProviderApplyConfiguration {
b := &ProxyProviderApplyConfiguration{}
b.WithName(name)
b.WithNamespace(namespace)
b.WithKind("ProxyProvider")
b.WithAPIVersion("proxyprovider.t000-n.de/v1alpha1")
return b
}
func (b ProxyProviderApplyConfiguration) IsApplyConfiguration() {}
// WithKind sets the Kind field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Kind field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithKind(value string) *ProxyProviderApplyConfiguration {
b.TypeMetaApplyConfiguration.Kind = &value
return b
}
// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the APIVersion field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithAPIVersion(value string) *ProxyProviderApplyConfiguration {
b.TypeMetaApplyConfiguration.APIVersion = &value
return b
}
// WithName sets the Name field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Name field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithName(value string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Name = &value
return b
}
// WithGenerateName sets the GenerateName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the GenerateName field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithGenerateName(value string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.GenerateName = &value
return b
}
// WithNamespace sets the Namespace field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Namespace field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithNamespace(value string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Namespace = &value
return b
}
// WithUID sets the UID field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the UID field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithUID(value types.UID) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.UID = &value
return b
}
// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ResourceVersion field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithResourceVersion(value string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.ResourceVersion = &value
return b
}
// WithGeneration sets the Generation field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Generation field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithGeneration(value int64) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.Generation = &value
return b
}
// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the CreationTimestamp field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.CreationTimestamp = &value
return b
}
// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionTimestamp field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value
return b
}
// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value
return b
}
// WithLabels puts the entries into the Labels field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Labels field,
// overwriting an existing map entries in Labels field with the same key.
func (b *ProxyProviderApplyConfiguration) WithLabels(entries map[string]string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries))
}
for k, v := range entries {
b.ObjectMetaApplyConfiguration.Labels[k] = v
}
return b
}
// WithAnnotations puts the entries into the Annotations field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, the entries provided by each call will be put on the Annotations field,
// overwriting an existing map entries in Annotations field with the same key.
func (b *ProxyProviderApplyConfiguration) WithAnnotations(entries map[string]string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 {
b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries))
}
for k, v := range entries {
b.ObjectMetaApplyConfiguration.Annotations[k] = v
}
return b
}
// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the OwnerReferences field.
func (b *ProxyProviderApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
for i := range values {
if values[i] == nil {
panic("nil value passed to WithOwnerReferences")
}
b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i])
}
return b
}
// WithFinalizers adds the given value to the Finalizers field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the Finalizers field.
func (b *ProxyProviderApplyConfiguration) WithFinalizers(values ...string) *ProxyProviderApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
for i := range values {
b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i])
}
return b
}
func (b *ProxyProviderApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
if b.ObjectMetaApplyConfiguration == nil {
b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{}
}
}
// WithSpec sets the Spec field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Spec field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithSpec(value *ProxyProviderSpecApplyConfiguration) *ProxyProviderApplyConfiguration {
b.Spec = value
return b
}
// WithStatus sets the Status field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Status field is set to the value of the last call.
func (b *ProxyProviderApplyConfiguration) WithStatus(value *ProxyProviderStatusApplyConfiguration) *ProxyProviderApplyConfiguration {
b.Status = value
return b
}
// GetKind retrieves the value of the Kind field in the declarative configuration.
func (b *ProxyProviderApplyConfiguration) GetKind() *string {
return b.TypeMetaApplyConfiguration.Kind
}
// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration.
func (b *ProxyProviderApplyConfiguration) GetAPIVersion() *string {
return b.TypeMetaApplyConfiguration.APIVersion
}
// GetName retrieves the value of the Name field in the declarative configuration.
func (b *ProxyProviderApplyConfiguration) GetName() *string {
b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Name
}
// GetNamespace retrieves the value of the Namespace field in the declarative configuration.
func (b *ProxyProviderApplyConfiguration) GetNamespace() *string {
b.ensureObjectMetaApplyConfigurationExists()
return b.ObjectMetaApplyConfiguration.Namespace
}
@@ -0,0 +1,75 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
// ProxyProviderSpecApplyConfiguration represents a declarative configuration of the ProxyProviderSpec type for use
// with apply.
type ProxyProviderSpecApplyConfiguration struct {
Name *string `json:"name,omitempty"`
AuthorizationFlow *string `json:"authorization_flow,omitempty"`
InvalidationFlow *string `json:"invalidation_flow,omitempty"`
ExternalHost *string `json:"external_host,omitempty"`
Outpost *string `json:"outpost,omitempty"`
}
// ProxyProviderSpecApplyConfiguration constructs a declarative configuration of the ProxyProviderSpec type for use with
// apply.
func ProxyProviderSpec() *ProxyProviderSpecApplyConfiguration {
return &ProxyProviderSpecApplyConfiguration{}
}
// WithName sets the Name field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Name field is set to the value of the last call.
func (b *ProxyProviderSpecApplyConfiguration) WithName(value string) *ProxyProviderSpecApplyConfiguration {
b.Name = &value
return b
}
// WithAuthorizationFlow sets the AuthorizationFlow field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the AuthorizationFlow field is set to the value of the last call.
func (b *ProxyProviderSpecApplyConfiguration) WithAuthorizationFlow(value string) *ProxyProviderSpecApplyConfiguration {
b.AuthorizationFlow = &value
return b
}
// WithInvalidationFlow sets the InvalidationFlow field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the InvalidationFlow field is set to the value of the last call.
func (b *ProxyProviderSpecApplyConfiguration) WithInvalidationFlow(value string) *ProxyProviderSpecApplyConfiguration {
b.InvalidationFlow = &value
return b
}
// WithExternalHost sets the ExternalHost field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ExternalHost field is set to the value of the last call.
func (b *ProxyProviderSpecApplyConfiguration) WithExternalHost(value string) *ProxyProviderSpecApplyConfiguration {
b.ExternalHost = &value
return b
}
// WithOutpost sets the Outpost field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Outpost field is set to the value of the last call.
func (b *ProxyProviderSpecApplyConfiguration) WithOutpost(value string) *ProxyProviderSpecApplyConfiguration {
b.Outpost = &value
return b
}
@@ -0,0 +1,39 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
// ProxyProviderStatusApplyConfiguration represents a declarative configuration of the ProxyProviderStatus type for use
// with apply.
type ProxyProviderStatusApplyConfiguration struct {
PK *string `json:"pk,omitempty"`
}
// ProxyProviderStatusApplyConfiguration constructs a declarative configuration of the ProxyProviderStatus type for use with
// apply.
func ProxyProviderStatus() *ProxyProviderStatusApplyConfiguration {
return &ProxyProviderStatusApplyConfiguration{}
}
// WithPK sets the PK field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the PK field is set to the value of the last call.
func (b *ProxyProviderStatusApplyConfiguration) WithPK(value string) *ProxyProviderStatusApplyConfiguration {
b.PK = &value
return b
}
@@ -1,50 +0,0 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by applyconfiguration-gen. DO NOT EDIT.
package v1alpha1
// FooSpecApplyConfiguration represents a declarative configuration of the FooSpec type for use
// with apply.
//
// FooSpec is the spec for a Foo resource
type FooSpecApplyConfiguration struct {
DeploymentName *string `json:"deploymentName,omitempty"`
Replicas *int32 `json:"replicas,omitempty"`
}
// FooSpecApplyConfiguration constructs a declarative configuration of the FooSpec type for use with
// apply.
func FooSpec() *FooSpecApplyConfiguration {
return &FooSpecApplyConfiguration{}
}
// WithDeploymentName sets the DeploymentName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the DeploymentName field is set to the value of the last call.
func (b *FooSpecApplyConfiguration) WithDeploymentName(value string) *FooSpecApplyConfiguration {
b.DeploymentName = &value
return b
}
// WithReplicas sets the Replicas field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Replicas field is set to the value of the last call.
func (b *FooSpecApplyConfiguration) WithReplicas(value int32) *FooSpecApplyConfiguration {
b.Replicas = &value
return b
}
+29 -9
View File
@@ -19,9 +19,13 @@ limitations under the License.
package applyconfiguration package applyconfiguration
import ( import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1" v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/application/v1alpha1"
internal "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/internal" internal "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/internal"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/samplecontroller/v1alpha1" applyconfigurationpolicybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/policybinding/v1alpha1"
applyconfigurationproxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/proxyprovider/v1alpha1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
managedfields "k8s.io/apimachinery/pkg/util/managedfields" managedfields "k8s.io/apimachinery/pkg/util/managedfields"
@@ -31,13 +35,29 @@ import (
// apply configuration type exists for the given GroupVersionKind. // apply configuration type exists for the given GroupVersionKind.
func ForKind(kind schema.GroupVersionKind) interface{} { func ForKind(kind schema.GroupVersionKind) interface{} {
switch kind { switch kind {
// Group=samplecontroller.k8s.io, Version=v1alpha1 // Group=application.t000-n.de, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithKind("Foo"): case v1alpha1.SchemeGroupVersion.WithKind("Application"):
return &samplecontrollerv1alpha1.FooApplyConfiguration{} return &applicationv1alpha1.ApplicationApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("FooSpec"): case v1alpha1.SchemeGroupVersion.WithKind("ApplicationSpec"):
return &samplecontrollerv1alpha1.FooSpecApplyConfiguration{} return &applicationv1alpha1.ApplicationSpecApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("FooStatus"): case v1alpha1.SchemeGroupVersion.WithKind("ApplicationStatus"):
return &samplecontrollerv1alpha1.FooStatusApplyConfiguration{} return &applicationv1alpha1.ApplicationStatusApplyConfiguration{}
// Group=policybinding.t000-n.de, Version=v1alpha1
case policybindingv1alpha1.SchemeGroupVersion.WithKind("PolicyBinding"):
return &applyconfigurationpolicybindingv1alpha1.PolicyBindingApplyConfiguration{}
case policybindingv1alpha1.SchemeGroupVersion.WithKind("PolicyBindingSpec"):
return &applyconfigurationpolicybindingv1alpha1.PolicyBindingSpecApplyConfiguration{}
case policybindingv1alpha1.SchemeGroupVersion.WithKind("PolicyBindingStatus"):
return &applyconfigurationpolicybindingv1alpha1.PolicyBindingStatusApplyConfiguration{}
// Group=proxyprovider.t000-n.de, Version=v1alpha1
case proxyproviderv1alpha1.SchemeGroupVersion.WithKind("ProxyProvider"):
return &applyconfigurationproxyproviderv1alpha1.ProxyProviderApplyConfiguration{}
case proxyproviderv1alpha1.SchemeGroupVersion.WithKind("ProxyProviderSpec"):
return &applyconfigurationproxyproviderv1alpha1.ProxyProviderSpecApplyConfiguration{}
case proxyproviderv1alpha1.SchemeGroupVersion.WithKind("ProxyProviderStatus"):
return &applyconfigurationproxyproviderv1alpha1.ProxyProviderStatusApplyConfiguration{}
} }
return nil return nil
+34 -8
View File
@@ -22,7 +22,9 @@ import (
fmt "fmt" fmt "fmt"
http "net/http" http "net/http"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1" applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/application/v1alpha1"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/policybinding/v1alpha1"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/proxyprovider/v1alpha1"
discovery "k8s.io/client-go/discovery" discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
flowcontrol "k8s.io/client-go/util/flowcontrol" flowcontrol "k8s.io/client-go/util/flowcontrol"
@@ -30,18 +32,32 @@ import (
type Interface interface { type Interface interface {
Discovery() discovery.DiscoveryInterface Discovery() discovery.DiscoveryInterface
SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface ApplicationV1alpha1() applicationv1alpha1.ApplicationV1alpha1Interface
PolicyBindingV1alpha1() policybindingv1alpha1.PolicyBindingV1alpha1Interface
ProxyproviderV1alpha1() proxyproviderv1alpha1.ProxyproviderV1alpha1Interface
} }
// Clientset contains the clients for groups. // Clientset contains the clients for groups.
type Clientset struct { type Clientset struct {
*discovery.DiscoveryClient *discovery.DiscoveryClient
samplecontrollerV1alpha1 *samplecontrollerv1alpha1.SamplecontrollerV1alpha1Client applicationV1alpha1 *applicationv1alpha1.ApplicationV1alpha1Client
policyBindingV1alpha1 *policybindingv1alpha1.PolicyBindingV1alpha1Client
proxyproviderV1alpha1 *proxyproviderv1alpha1.ProxyproviderV1alpha1Client
} }
// SamplecontrollerV1alpha1 retrieves the SamplecontrollerV1alpha1Client // ApplicationV1alpha1 retrieves the ApplicationV1alpha1Client
func (c *Clientset) SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface { func (c *Clientset) ApplicationV1alpha1() applicationv1alpha1.ApplicationV1alpha1Interface {
return c.samplecontrollerV1alpha1 return c.applicationV1alpha1
}
// PolicyBindingV1alpha1 retrieves the PolicyBindingV1alpha1Client
func (c *Clientset) PolicyBindingV1alpha1() policybindingv1alpha1.PolicyBindingV1alpha1Interface {
return c.policyBindingV1alpha1
}
// ProxyproviderV1alpha1 retrieves the ProxyproviderV1alpha1Client
func (c *Clientset) ProxyproviderV1alpha1() proxyproviderv1alpha1.ProxyproviderV1alpha1Interface {
return c.proxyproviderV1alpha1
} }
// Discovery retrieves the DiscoveryClient // Discovery retrieves the DiscoveryClient
@@ -88,7 +104,15 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset,
var cs Clientset var cs Clientset
var err error var err error
cs.samplecontrollerV1alpha1, err = samplecontrollerv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) cs.applicationV1alpha1, err = applicationv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
if err != nil {
return nil, err
}
cs.policyBindingV1alpha1, err = policybindingv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
if err != nil {
return nil, err
}
cs.proxyproviderV1alpha1, err = proxyproviderv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -113,7 +137,9 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
// New creates a new Clientset for the given RESTClient. // New creates a new Clientset for the given RESTClient.
func New(c rest.Interface) *Clientset { func New(c rest.Interface) *Clientset {
var cs Clientset var cs Clientset
cs.samplecontrollerV1alpha1 = samplecontrollerv1alpha1.New(c) cs.applicationV1alpha1 = applicationv1alpha1.New(c)
cs.policyBindingV1alpha1 = policybindingv1alpha1.New(c)
cs.proxyproviderV1alpha1 = proxyproviderv1alpha1.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &cs return &cs
@@ -21,8 +21,12 @@ package fake
import ( import (
applyconfiguration "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration" applyconfiguration "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1" applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/application/v1alpha1"
fakesamplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake" fakeapplicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/application/v1alpha1/fake"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/policybinding/v1alpha1"
fakepolicybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/policybinding/v1alpha1/fake"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/proxyprovider/v1alpha1"
fakeproxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/proxyprovider/v1alpha1/fake"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
@@ -136,7 +140,17 @@ var (
_ testing.FakeClient = &Clientset{} _ testing.FakeClient = &Clientset{}
) )
// SamplecontrollerV1alpha1 retrieves the SamplecontrollerV1alpha1Client // ApplicationV1alpha1 retrieves the ApplicationV1alpha1Client
func (c *Clientset) SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface { func (c *Clientset) ApplicationV1alpha1() applicationv1alpha1.ApplicationV1alpha1Interface {
return &fakesamplecontrollerv1alpha1.FakeSamplecontrollerV1alpha1{Fake: &c.Fake} return &fakeapplicationv1alpha1.FakeApplicationV1alpha1{Fake: &c.Fake}
}
// PolicyBindingV1alpha1 retrieves the PolicyBindingV1alpha1Client
func (c *Clientset) PolicyBindingV1alpha1() policybindingv1alpha1.PolicyBindingV1alpha1Interface {
return &fakepolicybindingv1alpha1.FakePolicyBindingV1alpha1{Fake: &c.Fake}
}
// ProxyproviderV1alpha1 retrieves the ProxyproviderV1alpha1Client
func (c *Clientset) ProxyproviderV1alpha1() proxyproviderv1alpha1.ProxyproviderV1alpha1Interface {
return &fakeproxyproviderv1alpha1.FakeProxyproviderV1alpha1{Fake: &c.Fake}
} }
@@ -19,7 +19,9 @@ limitations under the License.
package fake package fake
import ( import (
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1" applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -31,7 +33,9 @@ var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme) var codecs = serializer.NewCodecFactory(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{ var localSchemeBuilder = runtime.SchemeBuilder{
samplecontrollerv1alpha1.AddToScheme, applicationv1alpha1.AddToScheme,
policybindingv1alpha1.AddToScheme,
proxyproviderv1alpha1.AddToScheme,
} }
// AddToScheme adds all types of this clientset into the given scheme. This allows composition // AddToScheme adds all types of this clientset into the given scheme. This allows composition
@@ -19,7 +19,9 @@ limitations under the License.
package scheme package scheme
import ( import (
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1" applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -31,7 +33,9 @@ var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme) var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{ var localSchemeBuilder = runtime.SchemeBuilder{
samplecontrollerv1alpha1.AddToScheme, applicationv1alpha1.AddToScheme,
policybindingv1alpha1.AddToScheme,
proxyproviderv1alpha1.AddToScheme,
} }
// AddToScheme adds all types of this clientset into the given scheme. This allows composition // AddToScheme adds all types of this clientset into the given scheme. This allows composition
@@ -0,0 +1,74 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
context "context"
applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
applyconfigurationapplicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/application/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype"
)
// ApplicationsGetter has a method to return a ApplicationInterface.
// A group's client should implement this interface.
type ApplicationsGetter interface {
Applications(namespace string) ApplicationInterface
}
// ApplicationInterface has methods to work with Application resources.
type ApplicationInterface interface {
Create(ctx context.Context, application *applicationv1alpha1.Application, opts v1.CreateOptions) (*applicationv1alpha1.Application, error)
Update(ctx context.Context, application *applicationv1alpha1.Application, opts v1.UpdateOptions) (*applicationv1alpha1.Application, error)
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
UpdateStatus(ctx context.Context, application *applicationv1alpha1.Application, opts v1.UpdateOptions) (*applicationv1alpha1.Application, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*applicationv1alpha1.Application, error)
List(ctx context.Context, opts v1.ListOptions) (*applicationv1alpha1.ApplicationList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *applicationv1alpha1.Application, err error)
Apply(ctx context.Context, application *applyconfigurationapplicationv1alpha1.ApplicationApplyConfiguration, opts v1.ApplyOptions) (result *applicationv1alpha1.Application, err error)
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
ApplyStatus(ctx context.Context, application *applyconfigurationapplicationv1alpha1.ApplicationApplyConfiguration, opts v1.ApplyOptions) (result *applicationv1alpha1.Application, err error)
ApplicationExpansion
}
// applications implements ApplicationInterface
type applications struct {
*gentype.ClientWithListAndApply[*applicationv1alpha1.Application, *applicationv1alpha1.ApplicationList, *applyconfigurationapplicationv1alpha1.ApplicationApplyConfiguration]
}
// newApplications returns a Applications
func newApplications(c *ApplicationV1alpha1Client, namespace string) *applications {
return &applications{
gentype.NewClientWithListAndApply[*applicationv1alpha1.Application, *applicationv1alpha1.ApplicationList, *applyconfigurationapplicationv1alpha1.ApplicationApplyConfiguration](
"applications",
c.RESTClient(),
scheme.ParameterCodec,
namespace,
func() *applicationv1alpha1.Application { return &applicationv1alpha1.Application{} },
func() *applicationv1alpha1.ApplicationList { return &applicationv1alpha1.ApplicationList{} },
),
}
}
@@ -21,29 +21,29 @@ package v1alpha1
import ( import (
http "net/http" http "net/http"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1" applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme" scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
) )
type SamplecontrollerV1alpha1Interface interface { type ApplicationV1alpha1Interface interface {
RESTClient() rest.Interface RESTClient() rest.Interface
FoosGetter ApplicationsGetter
} }
// SamplecontrollerV1alpha1Client is used to interact with features provided by the samplecontroller.k8s.io group. // ApplicationV1alpha1Client is used to interact with features provided by the application.t000-n.de group.
type SamplecontrollerV1alpha1Client struct { type ApplicationV1alpha1Client struct {
restClient rest.Interface restClient rest.Interface
} }
func (c *SamplecontrollerV1alpha1Client) Foos(namespace string) FooInterface { func (c *ApplicationV1alpha1Client) Applications(namespace string) ApplicationInterface {
return newFoos(c, namespace) return newApplications(c, namespace)
} }
// NewForConfig creates a new SamplecontrollerV1alpha1Client for the given config. // NewForConfig creates a new ApplicationV1alpha1Client for the given config.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c). // where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(c *rest.Config) (*SamplecontrollerV1alpha1Client, error) { func NewForConfig(c *rest.Config) (*ApplicationV1alpha1Client, error) {
config := *c config := *c
setConfigDefaults(&config) setConfigDefaults(&config)
httpClient, err := rest.HTTPClientFor(&config) httpClient, err := rest.HTTPClientFor(&config)
@@ -53,21 +53,21 @@ func NewForConfig(c *rest.Config) (*SamplecontrollerV1alpha1Client, error) {
return NewForConfigAndClient(&config, httpClient) return NewForConfigAndClient(&config, httpClient)
} }
// NewForConfigAndClient creates a new SamplecontrollerV1alpha1Client for the given config and http client. // NewForConfigAndClient creates a new ApplicationV1alpha1Client for the given config and http client.
// Note the http client provided takes precedence over the configured transport values. // Note the http client provided takes precedence over the configured transport values.
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SamplecontrollerV1alpha1Client, error) { func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ApplicationV1alpha1Client, error) {
config := *c config := *c
setConfigDefaults(&config) setConfigDefaults(&config)
client, err := rest.RESTClientForConfigAndClient(&config, h) client, err := rest.RESTClientForConfigAndClient(&config, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &SamplecontrollerV1alpha1Client{client}, nil return &ApplicationV1alpha1Client{client}, nil
} }
// NewForConfigOrDie creates a new SamplecontrollerV1alpha1Client for the given config and // NewForConfigOrDie creates a new ApplicationV1alpha1Client for the given config and
// panics if there is an error in the config. // panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *SamplecontrollerV1alpha1Client { func NewForConfigOrDie(c *rest.Config) *ApplicationV1alpha1Client {
client, err := NewForConfig(c) client, err := NewForConfig(c)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -75,13 +75,13 @@ func NewForConfigOrDie(c *rest.Config) *SamplecontrollerV1alpha1Client {
return client return client
} }
// New creates a new SamplecontrollerV1alpha1Client for the given RESTClient. // New creates a new ApplicationV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *SamplecontrollerV1alpha1Client { func New(c rest.Interface) *ApplicationV1alpha1Client {
return &SamplecontrollerV1alpha1Client{c} return &ApplicationV1alpha1Client{c}
} }
func setConfigDefaults(config *rest.Config) { func setConfigDefaults(config *rest.Config) {
gv := samplecontrollerv1alpha1.SchemeGroupVersion gv := applicationv1alpha1.SchemeGroupVersion
config.GroupVersion = &gv config.GroupVersion = &gv
config.APIPath = "/apis" config.APIPath = "/apis"
config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion()
@@ -93,7 +93,7 @@ func setConfigDefaults(config *rest.Config) {
// RESTClient returns a RESTClient that is used to communicate // RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation. // with API server by this client implementation.
func (c *SamplecontrollerV1alpha1Client) RESTClient() rest.Interface { func (c *ApplicationV1alpha1Client) RESTClient() rest.Interface {
if c == nil { if c == nil {
return nil return nil
} }
@@ -0,0 +1,53 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/application/v1alpha1"
typedapplicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/application/v1alpha1"
gentype "k8s.io/client-go/gentype"
)
// fakeApplications implements ApplicationInterface
type fakeApplications struct {
*gentype.FakeClientWithListAndApply[*v1alpha1.Application, *v1alpha1.ApplicationList, *applicationv1alpha1.ApplicationApplyConfiguration]
Fake *FakeApplicationV1alpha1
}
func newFakeApplications(fake *FakeApplicationV1alpha1, namespace string) typedapplicationv1alpha1.ApplicationInterface {
return &fakeApplications{
gentype.NewFakeClientWithListAndApply[*v1alpha1.Application, *v1alpha1.ApplicationList, *applicationv1alpha1.ApplicationApplyConfiguration](
fake.Fake,
namespace,
v1alpha1.SchemeGroupVersion.WithResource("applications"),
v1alpha1.SchemeGroupVersion.WithKind("Application"),
func() *v1alpha1.Application { return &v1alpha1.Application{} },
func() *v1alpha1.ApplicationList { return &v1alpha1.ApplicationList{} },
func(dst, src *v1alpha1.ApplicationList) { dst.ListMeta = src.ListMeta },
func(list *v1alpha1.ApplicationList) []*v1alpha1.Application {
return gentype.ToPointerSlice(list.Items)
},
func(list *v1alpha1.ApplicationList, items []*v1alpha1.Application) {
list.Items = gentype.FromPointerSlice(items)
},
),
fake,
}
}
@@ -19,22 +19,22 @@ limitations under the License.
package fake package fake
import ( import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1" v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/application/v1alpha1"
rest "k8s.io/client-go/rest" rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing" testing "k8s.io/client-go/testing"
) )
type FakeSamplecontrollerV1alpha1 struct { type FakeApplicationV1alpha1 struct {
*testing.Fake *testing.Fake
} }
func (c *FakeSamplecontrollerV1alpha1) Foos(namespace string) v1alpha1.FooInterface { func (c *FakeApplicationV1alpha1) Applications(namespace string) v1alpha1.ApplicationInterface {
return newFakeFoos(c, namespace) return newFakeApplications(c, namespace)
} }
// RESTClient returns a RESTClient that is used to communicate // RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation. // with API server by this client implementation.
func (c *FakeSamplecontrollerV1alpha1) RESTClient() rest.Interface { func (c *FakeApplicationV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient var ret *rest.RESTClient
return ret return ret
} }
@@ -18,4 +18,4 @@ limitations under the License.
package v1alpha1 package v1alpha1
type FooExpansion interface{} type ApplicationExpansion interface{}
@@ -0,0 +1,20 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1alpha1
@@ -0,0 +1,20 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake
@@ -0,0 +1,53 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/policybinding/v1alpha1"
typedpolicybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/policybinding/v1alpha1"
gentype "k8s.io/client-go/gentype"
)
// fakePolicyBindings implements PolicyBindingInterface
type fakePolicyBindings struct {
*gentype.FakeClientWithListAndApply[*v1alpha1.PolicyBinding, *v1alpha1.PolicyBindingList, *policybindingv1alpha1.PolicyBindingApplyConfiguration]
Fake *FakePolicyBindingV1alpha1
}
func newFakePolicyBindings(fake *FakePolicyBindingV1alpha1, namespace string) typedpolicybindingv1alpha1.PolicyBindingInterface {
return &fakePolicyBindings{
gentype.NewFakeClientWithListAndApply[*v1alpha1.PolicyBinding, *v1alpha1.PolicyBindingList, *policybindingv1alpha1.PolicyBindingApplyConfiguration](
fake.Fake,
namespace,
v1alpha1.SchemeGroupVersion.WithResource("policybindings"),
v1alpha1.SchemeGroupVersion.WithKind("PolicyBinding"),
func() *v1alpha1.PolicyBinding { return &v1alpha1.PolicyBinding{} },
func() *v1alpha1.PolicyBindingList { return &v1alpha1.PolicyBindingList{} },
func(dst, src *v1alpha1.PolicyBindingList) { dst.ListMeta = src.ListMeta },
func(list *v1alpha1.PolicyBindingList) []*v1alpha1.PolicyBinding {
return gentype.ToPointerSlice(list.Items)
},
func(list *v1alpha1.PolicyBindingList, items []*v1alpha1.PolicyBinding) {
list.Items = gentype.FromPointerSlice(items)
},
),
fake,
}
}
@@ -0,0 +1,40 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/policybinding/v1alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakePolicyBindingV1alpha1 struct {
*testing.Fake
}
func (c *FakePolicyBindingV1alpha1) PolicyBindings(namespace string) v1alpha1.PolicyBindingInterface {
return newFakePolicyBindings(c, namespace)
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakePolicyBindingV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}
@@ -14,3 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
type PolicyBindingExpansion interface{}
@@ -0,0 +1,74 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
context "context"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
applyconfigurationpolicybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/policybinding/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype"
)
// PolicyBindingsGetter has a method to return a PolicyBindingInterface.
// A group's client should implement this interface.
type PolicyBindingsGetter interface {
PolicyBindings(namespace string) PolicyBindingInterface
}
// PolicyBindingInterface has methods to work with PolicyBinding resources.
type PolicyBindingInterface interface {
Create(ctx context.Context, policyBinding *policybindingv1alpha1.PolicyBinding, opts v1.CreateOptions) (*policybindingv1alpha1.PolicyBinding, error)
Update(ctx context.Context, policyBinding *policybindingv1alpha1.PolicyBinding, opts v1.UpdateOptions) (*policybindingv1alpha1.PolicyBinding, error)
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
UpdateStatus(ctx context.Context, policyBinding *policybindingv1alpha1.PolicyBinding, opts v1.UpdateOptions) (*policybindingv1alpha1.PolicyBinding, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*policybindingv1alpha1.PolicyBinding, error)
List(ctx context.Context, opts v1.ListOptions) (*policybindingv1alpha1.PolicyBindingList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *policybindingv1alpha1.PolicyBinding, err error)
Apply(ctx context.Context, policyBinding *applyconfigurationpolicybindingv1alpha1.PolicyBindingApplyConfiguration, opts v1.ApplyOptions) (result *policybindingv1alpha1.PolicyBinding, err error)
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
ApplyStatus(ctx context.Context, policyBinding *applyconfigurationpolicybindingv1alpha1.PolicyBindingApplyConfiguration, opts v1.ApplyOptions) (result *policybindingv1alpha1.PolicyBinding, err error)
PolicyBindingExpansion
}
// policyBindings implements PolicyBindingInterface
type policyBindings struct {
*gentype.ClientWithListAndApply[*policybindingv1alpha1.PolicyBinding, *policybindingv1alpha1.PolicyBindingList, *applyconfigurationpolicybindingv1alpha1.PolicyBindingApplyConfiguration]
}
// newPolicyBindings returns a PolicyBindings
func newPolicyBindings(c *PolicyBindingV1alpha1Client, namespace string) *policyBindings {
return &policyBindings{
gentype.NewClientWithListAndApply[*policybindingv1alpha1.PolicyBinding, *policybindingv1alpha1.PolicyBindingList, *applyconfigurationpolicybindingv1alpha1.PolicyBindingApplyConfiguration](
"policybindings",
c.RESTClient(),
scheme.ParameterCodec,
namespace,
func() *policybindingv1alpha1.PolicyBinding { return &policybindingv1alpha1.PolicyBinding{} },
func() *policybindingv1alpha1.PolicyBindingList { return &policybindingv1alpha1.PolicyBindingList{} },
),
}
}
@@ -0,0 +1,101 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
http "net/http"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type PolicyBindingV1alpha1Interface interface {
RESTClient() rest.Interface
PolicyBindingsGetter
}
// PolicyBindingV1alpha1Client is used to interact with features provided by the policybinding.t000-n.de group.
type PolicyBindingV1alpha1Client struct {
restClient rest.Interface
}
func (c *PolicyBindingV1alpha1Client) PolicyBindings(namespace string) PolicyBindingInterface {
return newPolicyBindings(c, namespace)
}
// NewForConfig creates a new PolicyBindingV1alpha1Client for the given config.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(c *rest.Config) (*PolicyBindingV1alpha1Client, error) {
config := *c
setConfigDefaults(&config)
httpClient, err := rest.HTTPClientFor(&config)
if err != nil {
return nil, err
}
return NewForConfigAndClient(&config, httpClient)
}
// NewForConfigAndClient creates a new PolicyBindingV1alpha1Client for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*PolicyBindingV1alpha1Client, error) {
config := *c
setConfigDefaults(&config)
client, err := rest.RESTClientForConfigAndClient(&config, h)
if err != nil {
return nil, err
}
return &PolicyBindingV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new PolicyBindingV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *PolicyBindingV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new PolicyBindingV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *PolicyBindingV1alpha1Client {
return &PolicyBindingV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) {
gv := policybindingv1alpha1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *PolicyBindingV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}
@@ -0,0 +1,20 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1alpha1
@@ -0,0 +1,20 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake
@@ -0,0 +1,53 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/proxyprovider/v1alpha1"
typedproxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/proxyprovider/v1alpha1"
gentype "k8s.io/client-go/gentype"
)
// fakeProxyProviders implements ProxyProviderInterface
type fakeProxyProviders struct {
*gentype.FakeClientWithListAndApply[*v1alpha1.ProxyProvider, *v1alpha1.ProxyProviderList, *proxyproviderv1alpha1.ProxyProviderApplyConfiguration]
Fake *FakeProxyproviderV1alpha1
}
func newFakeProxyProviders(fake *FakeProxyproviderV1alpha1, namespace string) typedproxyproviderv1alpha1.ProxyProviderInterface {
return &fakeProxyProviders{
gentype.NewFakeClientWithListAndApply[*v1alpha1.ProxyProvider, *v1alpha1.ProxyProviderList, *proxyproviderv1alpha1.ProxyProviderApplyConfiguration](
fake.Fake,
namespace,
v1alpha1.SchemeGroupVersion.WithResource("proxyproviders"),
v1alpha1.SchemeGroupVersion.WithKind("ProxyProvider"),
func() *v1alpha1.ProxyProvider { return &v1alpha1.ProxyProvider{} },
func() *v1alpha1.ProxyProviderList { return &v1alpha1.ProxyProviderList{} },
func(dst, src *v1alpha1.ProxyProviderList) { dst.ListMeta = src.ListMeta },
func(list *v1alpha1.ProxyProviderList) []*v1alpha1.ProxyProvider {
return gentype.ToPointerSlice(list.Items)
},
func(list *v1alpha1.ProxyProviderList, items []*v1alpha1.ProxyProvider) {
list.Items = gentype.FromPointerSlice(items)
},
),
fake,
}
}
@@ -0,0 +1,40 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/proxyprovider/v1alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeProxyproviderV1alpha1 struct {
*testing.Fake
}
func (c *FakeProxyproviderV1alpha1) ProxyProviders(namespace string) v1alpha1.ProxyProviderInterface {
return newFakeProxyProviders(c, namespace)
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeProxyproviderV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}
@@ -1,5 +1,5 @@
/* /*
Copyright 2017 The Kubernetes Authors. Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -14,10 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package signals // Code generated by client-gen. DO NOT EDIT.
import ( package v1alpha1
"os"
)
var shutdownSignals = []os.Signal{os.Interrupt} type ProxyProviderExpansion interface{}
@@ -0,0 +1,74 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
context "context"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
applyconfigurationproxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/proxyprovider/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype"
)
// ProxyProvidersGetter has a method to return a ProxyProviderInterface.
// A group's client should implement this interface.
type ProxyProvidersGetter interface {
ProxyProviders(namespace string) ProxyProviderInterface
}
// ProxyProviderInterface has methods to work with ProxyProvider resources.
type ProxyProviderInterface interface {
Create(ctx context.Context, proxyProvider *proxyproviderv1alpha1.ProxyProvider, opts v1.CreateOptions) (*proxyproviderv1alpha1.ProxyProvider, error)
Update(ctx context.Context, proxyProvider *proxyproviderv1alpha1.ProxyProvider, opts v1.UpdateOptions) (*proxyproviderv1alpha1.ProxyProvider, error)
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
UpdateStatus(ctx context.Context, proxyProvider *proxyproviderv1alpha1.ProxyProvider, opts v1.UpdateOptions) (*proxyproviderv1alpha1.ProxyProvider, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*proxyproviderv1alpha1.ProxyProvider, error)
List(ctx context.Context, opts v1.ListOptions) (*proxyproviderv1alpha1.ProxyProviderList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *proxyproviderv1alpha1.ProxyProvider, err error)
Apply(ctx context.Context, proxyProvider *applyconfigurationproxyproviderv1alpha1.ProxyProviderApplyConfiguration, opts v1.ApplyOptions) (result *proxyproviderv1alpha1.ProxyProvider, err error)
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
ApplyStatus(ctx context.Context, proxyProvider *applyconfigurationproxyproviderv1alpha1.ProxyProviderApplyConfiguration, opts v1.ApplyOptions) (result *proxyproviderv1alpha1.ProxyProvider, err error)
ProxyProviderExpansion
}
// proxyProviders implements ProxyProviderInterface
type proxyProviders struct {
*gentype.ClientWithListAndApply[*proxyproviderv1alpha1.ProxyProvider, *proxyproviderv1alpha1.ProxyProviderList, *applyconfigurationproxyproviderv1alpha1.ProxyProviderApplyConfiguration]
}
// newProxyProviders returns a ProxyProviders
func newProxyProviders(c *ProxyproviderV1alpha1Client, namespace string) *proxyProviders {
return &proxyProviders{
gentype.NewClientWithListAndApply[*proxyproviderv1alpha1.ProxyProvider, *proxyproviderv1alpha1.ProxyProviderList, *applyconfigurationproxyproviderv1alpha1.ProxyProviderApplyConfiguration](
"proxyproviders",
c.RESTClient(),
scheme.ParameterCodec,
namespace,
func() *proxyproviderv1alpha1.ProxyProvider { return &proxyproviderv1alpha1.ProxyProvider{} },
func() *proxyproviderv1alpha1.ProxyProviderList { return &proxyproviderv1alpha1.ProxyProviderList{} },
),
}
}
@@ -0,0 +1,101 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
http "net/http"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type ProxyproviderV1alpha1Interface interface {
RESTClient() rest.Interface
ProxyProvidersGetter
}
// ProxyproviderV1alpha1Client is used to interact with features provided by the proxyprovider.t000-n.de group.
type ProxyproviderV1alpha1Client struct {
restClient rest.Interface
}
func (c *ProxyproviderV1alpha1Client) ProxyProviders(namespace string) ProxyProviderInterface {
return newProxyProviders(c, namespace)
}
// NewForConfig creates a new ProxyproviderV1alpha1Client for the given config.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(c *rest.Config) (*ProxyproviderV1alpha1Client, error) {
config := *c
setConfigDefaults(&config)
httpClient, err := rest.HTTPClientFor(&config)
if err != nil {
return nil, err
}
return NewForConfigAndClient(&config, httpClient)
}
// NewForConfigAndClient creates a new ProxyproviderV1alpha1Client for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ProxyproviderV1alpha1Client, error) {
config := *c
setConfigDefaults(&config)
client, err := rest.RESTClientForConfigAndClient(&config, h)
if err != nil {
return nil, err
}
return &ProxyproviderV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new ProxyproviderV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *ProxyproviderV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new ProxyproviderV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *ProxyproviderV1alpha1Client {
return &ProxyproviderV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) {
gv := proxyproviderv1alpha1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *ProxyproviderV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}
@@ -1,49 +0,0 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/samplecontroller/v1alpha1"
typedsamplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1"
gentype "k8s.io/client-go/gentype"
)
// fakeFoos implements FooInterface
type fakeFoos struct {
*gentype.FakeClientWithListAndApply[*v1alpha1.Foo, *v1alpha1.FooList, *samplecontrollerv1alpha1.FooApplyConfiguration]
Fake *FakeSamplecontrollerV1alpha1
}
func newFakeFoos(fake *FakeSamplecontrollerV1alpha1, namespace string) typedsamplecontrollerv1alpha1.FooInterface {
return &fakeFoos{
gentype.NewFakeClientWithListAndApply[*v1alpha1.Foo, *v1alpha1.FooList, *samplecontrollerv1alpha1.FooApplyConfiguration](
fake.Fake,
namespace,
v1alpha1.SchemeGroupVersion.WithResource("foos"),
v1alpha1.SchemeGroupVersion.WithKind("Foo"),
func() *v1alpha1.Foo { return &v1alpha1.Foo{} },
func() *v1alpha1.FooList { return &v1alpha1.FooList{} },
func(dst, src *v1alpha1.FooList) { dst.ListMeta = src.ListMeta },
func(list *v1alpha1.FooList) []*v1alpha1.Foo { return gentype.ToPointerSlice(list.Items) },
func(list *v1alpha1.FooList, items []*v1alpha1.Foo) { list.Items = gentype.FromPointerSlice(items) },
),
fake,
}
}
@@ -1,74 +0,0 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
context "context"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1"
applyconfigurationsamplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/applyconfiguration/samplecontroller/v1alpha1"
scheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype"
)
// FoosGetter has a method to return a FooInterface.
// A group's client should implement this interface.
type FoosGetter interface {
Foos(namespace string) FooInterface
}
// FooInterface has methods to work with Foo resources.
type FooInterface interface {
Create(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.CreateOptions) (*samplecontrollerv1alpha1.Foo, error)
Update(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.UpdateOptions) (*samplecontrollerv1alpha1.Foo, error)
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
UpdateStatus(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.UpdateOptions) (*samplecontrollerv1alpha1.Foo, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*samplecontrollerv1alpha1.Foo, error)
List(ctx context.Context, opts v1.ListOptions) (*samplecontrollerv1alpha1.FooList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *samplecontrollerv1alpha1.Foo, err error)
Apply(ctx context.Context, foo *applyconfigurationsamplecontrollerv1alpha1.FooApplyConfiguration, opts v1.ApplyOptions) (result *samplecontrollerv1alpha1.Foo, err error)
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
ApplyStatus(ctx context.Context, foo *applyconfigurationsamplecontrollerv1alpha1.FooApplyConfiguration, opts v1.ApplyOptions) (result *samplecontrollerv1alpha1.Foo, err error)
FooExpansion
}
// foos implements FooInterface
type foos struct {
*gentype.ClientWithListAndApply[*samplecontrollerv1alpha1.Foo, *samplecontrollerv1alpha1.FooList, *applyconfigurationsamplecontrollerv1alpha1.FooApplyConfiguration]
}
// newFoos returns a Foos
func newFoos(c *SamplecontrollerV1alpha1Client, namespace string) *foos {
return &foos{
gentype.NewClientWithListAndApply[*samplecontrollerv1alpha1.Foo, *samplecontrollerv1alpha1.FooList, *applyconfigurationsamplecontrollerv1alpha1.FooApplyConfiguration](
"foos",
c.RESTClient(),
scheme.ParameterCodec,
namespace,
func() *samplecontrollerv1alpha1.Foo { return &samplecontrollerv1alpha1.Foo{} },
func() *samplecontrollerv1alpha1.FooList { return &samplecontrollerv1alpha1.FooList{} },
),
}
}
@@ -16,11 +16,11 @@ limitations under the License.
// Code generated by informer-gen. DO NOT EDIT. // Code generated by informer-gen. DO NOT EDIT.
package samplecontroller package application
import ( import (
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/application/v1alpha1"
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces" internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/samplecontroller/v1alpha1"
) )
// Interface provides access to each of this group's versions. // Interface provides access to each of this group's versions.
@@ -22,10 +22,10 @@ import (
context "context" context "context"
time "time" time "time"
apissamplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1" apisapplicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
versioned "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" versioned "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces" internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
samplecontrollerv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/samplecontroller/v1alpha1" applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/application/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -33,38 +33,38 @@ import (
cache "k8s.io/client-go/tools/cache" cache "k8s.io/client-go/tools/cache"
) )
// FooInformer provides access to a shared informer and lister for // ApplicationInformer provides access to a shared informer and lister for
// Foos. // Applications.
type FooInformer interface { type ApplicationInformer interface {
Informer() cache.SharedIndexInformer Informer() cache.SharedIndexInformer
Lister() samplecontrollerv1alpha1.FooLister Lister() applicationv1alpha1.ApplicationLister
} }
type fooInformer struct { type applicationInformer struct {
factory internalinterfaces.SharedInformerFactory factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string namespace string
} }
// NewFooInformer constructs a new informer for Foo type. // NewApplicationInformer constructs a new informer for Application type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent // Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server. // one. This reduces memory footprint and number of connections to the server.
func NewFooInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { func NewApplicationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFooInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers}) return NewApplicationInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
} }
// NewFilteredFooInformer constructs a new informer for Foo type. // NewFilteredApplicationInformer constructs a new informer for Application type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent // Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server. // one. This reduces memory footprint and number of connections to the server.
func NewFilteredFooInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { func NewFilteredApplicationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return NewFooInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions}) return NewApplicationInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
} }
// NewFooInformerWithOptions constructs a new informer for Foo type with additional options. // NewApplicationInformerWithOptions constructs a new informer for Application type with additional options.
// Always prefer using an informer factory to get a shared informer instead of getting an independent // Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server. // one. This reduces memory footprint and number of connections to the server.
func NewFooInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer { func NewApplicationInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
gvr := schema.GroupVersionResource{Group: "samplecontroller.k8s.io", Version: "v1alpha1", Resource: "foos"} gvr := schema.GroupVersionResource{Group: "application.t000-n.de", Version: "v1alpha1", Resource: "applications"}
identifier := options.InformerName.WithResource(gvr) identifier := options.InformerName.WithResource(gvr)
tweakListOptions := options.TweakListOptions tweakListOptions := options.TweakListOptions
return cache.NewSharedIndexInformerWithOptions( return cache.NewSharedIndexInformerWithOptions(
@@ -73,28 +73,28 @@ func NewFooInformerWithOptions(client versioned.Interface, namespace string, opt
if tweakListOptions != nil { if tweakListOptions != nil {
tweakListOptions(&opts) tweakListOptions(&opts)
} }
return client.SamplecontrollerV1alpha1().Foos(namespace).List(context.Background(), opts) return client.ApplicationV1alpha1().Applications(namespace).List(context.Background(), opts)
}, },
WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) { WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil { if tweakListOptions != nil {
tweakListOptions(&opts) tweakListOptions(&opts)
} }
return client.SamplecontrollerV1alpha1().Foos(namespace).Watch(context.Background(), opts) return client.ApplicationV1alpha1().Applications(namespace).Watch(context.Background(), opts)
}, },
ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) { ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil { if tweakListOptions != nil {
tweakListOptions(&opts) tweakListOptions(&opts)
} }
return client.SamplecontrollerV1alpha1().Foos(namespace).List(ctx, opts) return client.ApplicationV1alpha1().Applications(namespace).List(ctx, opts)
}, },
WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil { if tweakListOptions != nil {
tweakListOptions(&opts) tweakListOptions(&opts)
} }
return client.SamplecontrollerV1alpha1().Foos(namespace).Watch(ctx, opts) return client.ApplicationV1alpha1().Applications(namespace).Watch(ctx, opts)
}, },
}, client), }, client),
&apissamplecontrollerv1alpha1.Foo{}, &apisapplicationv1alpha1.Application{},
cache.SharedIndexInformerOptions{ cache.SharedIndexInformerOptions{
ResyncPeriod: options.ResyncPeriod, ResyncPeriod: options.ResyncPeriod,
Indexers: options.Indexers, Indexers: options.Indexers,
@@ -103,14 +103,14 @@ func NewFooInformerWithOptions(client versioned.Interface, namespace string, opt
) )
} }
func (f *fooInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { func (f *applicationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFooInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions}) return NewApplicationInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
} }
func (f *fooInformer) Informer() cache.SharedIndexInformer { func (f *applicationInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apissamplecontrollerv1alpha1.Foo{}, f.defaultInformer) return f.factory.InformerFor(&apisapplicationv1alpha1.Application{}, f.defaultInformer)
} }
func (f *fooInformer) Lister() samplecontrollerv1alpha1.FooLister { func (f *applicationInformer) Lister() applicationv1alpha1.ApplicationLister {
return samplecontrollerv1alpha1.NewFooLister(f.Informer().GetIndexer()) return applicationv1alpha1.NewApplicationLister(f.Informer().GetIndexer())
} }
@@ -24,8 +24,8 @@ import (
// Interface provides access to all the informers in this group version. // Interface provides access to all the informers in this group version.
type Interface interface { type Interface interface {
// Foos returns a FooInformer. // Applications returns a ApplicationInformer.
Foos() FooInformer Applications() ApplicationInformer
} }
type version struct { type version struct {
@@ -39,7 +39,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
} }
// Foos returns a FooInformer. // Applications returns a ApplicationInformer.
func (v *version) Foos() FooInformer { func (v *version) Applications() ApplicationInformer {
return &fooInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} return &applicationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
} }
@@ -25,8 +25,10 @@ import (
time "time" time "time"
versioned "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" versioned "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
application "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/application"
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces" internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
samplecontroller "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/samplecontroller" policybinding "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/policybinding"
proxyprovider "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/proxyprovider"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
@@ -325,9 +327,19 @@ type SharedInformerFactory interface {
// client. // client.
InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer
Samplecontroller() samplecontroller.Interface Application() application.Interface
PolicyBinding() policybinding.Interface
Proxyprovider() proxyprovider.Interface
} }
func (f *sharedInformerFactory) Samplecontroller() samplecontroller.Interface { func (f *sharedInformerFactory) Application() application.Interface {
return samplecontroller.New(f, f.namespace, f.tweakListOptions) return application.New(f, f.namespace, f.tweakListOptions)
}
func (f *sharedInformerFactory) PolicyBinding() policybinding.Interface {
return policybinding.New(f, f.namespace, f.tweakListOptions)
}
func (f *sharedInformerFactory) Proxyprovider() proxyprovider.Interface {
return proxyprovider.New(f, f.namespace, f.tweakListOptions)
} }
@@ -21,7 +21,9 @@ package externalversions
import ( import (
fmt "fmt" fmt "fmt"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/samplecontroller/v1alpha1" v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
schema "k8s.io/apimachinery/pkg/runtime/schema" schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache" cache "k8s.io/client-go/tools/cache"
) )
@@ -52,9 +54,17 @@ func (f *genericInformer) Lister() cache.GenericLister {
// TODO extend this to unknown resources with a client pool // TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource { switch resource {
// Group=samplecontroller.k8s.io, Version=v1alpha1 // Group=application.t000-n.de, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("foos"): case v1alpha1.SchemeGroupVersion.WithResource("applications"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Samplecontroller().V1alpha1().Foos().Informer()}, nil return &genericInformer{resource: resource.GroupResource(), informer: f.Application().V1alpha1().Applications().Informer()}, nil
// Group=policybinding.t000-n.de, Version=v1alpha1
case policybindingv1alpha1.SchemeGroupVersion.WithResource("policybindings"):
return &genericInformer{resource: resource.GroupResource(), informer: f.PolicyBinding().V1alpha1().PolicyBindings().Informer()}, nil
// Group=proxyprovider.t000-n.de, Version=v1alpha1
case proxyproviderv1alpha1.SchemeGroupVersion.WithResource("proxyproviders"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Proxyprovider().V1alpha1().ProxyProviders().Informer()}, nil
} }
@@ -0,0 +1,46 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package policybinding
import (
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/policybinding/v1alpha1"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1alpha1 provides access to shared informers for resources in V1alpha1.
V1alpha1() v1alpha1.Interface
}
type group struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1alpha1 returns a new v1alpha1.Interface.
func (g *group) V1alpha1() v1alpha1.Interface {
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
}
@@ -0,0 +1,45 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// PolicyBindings returns a PolicyBindingInformer.
PolicyBindings() PolicyBindingInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// PolicyBindings returns a PolicyBindingInformer.
func (v *version) PolicyBindings() PolicyBindingInformer {
return &policyBindingInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
@@ -0,0 +1,116 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
context "context"
time "time"
apispolicybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
versioned "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
policybindingv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/policybinding/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// PolicyBindingInformer provides access to a shared informer and lister for
// PolicyBindings.
type PolicyBindingInformer interface {
Informer() cache.SharedIndexInformer
Lister() policybindingv1alpha1.PolicyBindingLister
}
type policyBindingInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewPolicyBindingInformer constructs a new informer for PolicyBinding type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPolicyBindingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewPolicyBindingInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredPolicyBindingInformer constructs a new informer for PolicyBinding type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPolicyBindingInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return NewPolicyBindingInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
}
// NewPolicyBindingInformerWithOptions constructs a new informer for PolicyBinding type with additional options.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPolicyBindingInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
gvr := schema.GroupVersionResource{Group: "policybinding.t000-n.de", Version: "v1alpha1", Resource: "policybindings"}
identifier := options.InformerName.WithResource(gvr)
tweakListOptions := options.TweakListOptions
return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
ListFunc: func(opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.PolicyBindingV1alpha1().PolicyBindings(namespace).List(context.Background(), opts)
},
WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.PolicyBindingV1alpha1().PolicyBindings(namespace).Watch(context.Background(), opts)
},
ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.PolicyBindingV1alpha1().PolicyBindings(namespace).List(ctx, opts)
},
WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.PolicyBindingV1alpha1().PolicyBindings(namespace).Watch(ctx, opts)
},
}, client),
&apispolicybindingv1alpha1.PolicyBinding{},
cache.SharedIndexInformerOptions{
ResyncPeriod: options.ResyncPeriod,
Indexers: options.Indexers,
Identifier: identifier,
},
)
}
func (f *policyBindingInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewPolicyBindingInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *policyBindingInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apispolicybindingv1alpha1.PolicyBinding{}, f.defaultInformer)
}
func (f *policyBindingInformer) Lister() policybindingv1alpha1.PolicyBindingLister {
return policybindingv1alpha1.NewPolicyBindingLister(f.Informer().GetIndexer())
}
@@ -0,0 +1,46 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package proxyprovider
import (
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/proxyprovider/v1alpha1"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1alpha1 provides access to shared informers for resources in V1alpha1.
V1alpha1() v1alpha1.Interface
}
type group struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1alpha1 returns a new v1alpha1.Interface.
func (g *group) V1alpha1() v1alpha1.Interface {
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
}
@@ -0,0 +1,45 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// ProxyProviders returns a ProxyProviderInformer.
ProxyProviders() ProxyProviderInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// ProxyProviders returns a ProxyProviderInformer.
func (v *version) ProxyProviders() ProxyProviderInformer {
return &proxyProviderInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
@@ -0,0 +1,116 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
context "context"
time "time"
apisproxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
versioned "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
internalinterfaces "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/internalinterfaces"
proxyproviderv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/listers/proxyprovider/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// ProxyProviderInformer provides access to a shared informer and lister for
// ProxyProviders.
type ProxyProviderInformer interface {
Informer() cache.SharedIndexInformer
Lister() proxyproviderv1alpha1.ProxyProviderLister
}
type proxyProviderInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewProxyProviderInformer constructs a new informer for ProxyProvider type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewProxyProviderInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewProxyProviderInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers})
}
// NewFilteredProxyProviderInformer constructs a new informer for ProxyProvider type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredProxyProviderInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return NewProxyProviderInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions})
}
// NewProxyProviderInformerWithOptions constructs a new informer for ProxyProvider type with additional options.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewProxyProviderInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer {
gvr := schema.GroupVersionResource{Group: "proxyprovider.t000-n.de", Version: "v1alpha1", Resource: "proxyproviders"}
identifier := options.InformerName.WithResource(gvr)
tweakListOptions := options.TweakListOptions
return cache.NewSharedIndexInformerWithOptions(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
ListFunc: func(opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.ProxyproviderV1alpha1().ProxyProviders(namespace).List(context.Background(), opts)
},
WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.ProxyproviderV1alpha1().ProxyProviders(namespace).Watch(context.Background(), opts)
},
ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.ProxyproviderV1alpha1().ProxyProviders(namespace).List(ctx, opts)
},
WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&opts)
}
return client.ProxyproviderV1alpha1().ProxyProviders(namespace).Watch(ctx, opts)
},
}, client),
&apisproxyproviderv1alpha1.ProxyProvider{},
cache.SharedIndexInformerOptions{
ResyncPeriod: options.ResyncPeriod,
Indexers: options.Indexers,
Identifier: identifier,
},
)
}
func (f *proxyProviderInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewProxyProviderInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions})
}
func (f *proxyProviderInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apisproxyproviderv1alpha1.ProxyProvider{}, f.defaultInformer)
}
func (f *proxyProviderInformer) Lister() proxyproviderv1alpha1.ProxyProviderLister {
return proxyproviderv1alpha1.NewProxyProviderLister(f.Informer().GetIndexer())
}
@@ -0,0 +1,70 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
applicationv1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
labels "k8s.io/apimachinery/pkg/labels"
listers "k8s.io/client-go/listers"
cache "k8s.io/client-go/tools/cache"
)
// ApplicationLister helps list Applications.
// All objects returned here must be treated as read-only.
type ApplicationLister interface {
// List lists all Applications in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*applicationv1alpha1.Application, err error)
// Applications returns an object that can list and get Applications.
Applications(namespace string) ApplicationNamespaceLister
ApplicationListerExpansion
}
// applicationLister implements the ApplicationLister interface.
type applicationLister struct {
listers.ResourceIndexer[*applicationv1alpha1.Application]
}
// NewApplicationLister returns a new ApplicationLister.
func NewApplicationLister(indexer cache.Indexer) ApplicationLister {
return &applicationLister{listers.New[*applicationv1alpha1.Application](indexer, applicationv1alpha1.Resource("application"))}
}
// Applications returns an object that can list and get Applications.
func (s *applicationLister) Applications(namespace string) ApplicationNamespaceLister {
return applicationNamespaceLister{listers.NewNamespaced[*applicationv1alpha1.Application](s.ResourceIndexer, namespace)}
}
// ApplicationNamespaceLister helps list and get Applications.
// All objects returned here must be treated as read-only.
type ApplicationNamespaceLister interface {
// List lists all Applications in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*applicationv1alpha1.Application, err error)
// Get retrieves the Application from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*applicationv1alpha1.Application, error)
ApplicationNamespaceListerExpansion
}
// applicationNamespaceLister implements the ApplicationNamespaceLister
// interface.
type applicationNamespaceLister struct {
listers.ResourceIndexer[*applicationv1alpha1.Application]
}

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