Full Code of redhat-cop/operator-utils for AI

master 09e27b5626f9 cached
121 files
489.2 KB
163.9k tokens
342 symbols
1 requests
Download .txt
Showing preview only (525K chars total). Download the full file or copy to clipboard to get everything.
Repository: redhat-cop/operator-utils
Branch: master
Commit: 09e27b5626f9
Files: 121
Total size: 489.2 KB

Directory structure:
gitextract_fz5mf0kc/

├── .github/
│   └── workflows/
│       ├── pr.yaml
│       └── push.yaml
├── .gitignore
├── Dockerfile
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── api/
│   └── v1alpha1/
│       ├── enforcingcrd_types.go
│       ├── enforcingpatch_types.go
│       ├── enforcingreconcilerstatus.go
│       ├── groupversion_info.go
│       ├── lockedpatch.go
│       ├── lockedresource.go
│       ├── mycrd_types.go
│       ├── templatedenforcingcrd_types.go
│       └── zz_generated.deepcopy.go
├── ci.Dockerfile
├── config/
│   ├── certmanager/
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── crd/
│   │   ├── bases/
│   │   │   ├── operator-utils.example.io_enforcingcrds.yaml
│   │   │   ├── operator-utils.example.io_enforcingpatches.yaml
│   │   │   ├── operator-utils.example.io_mycrds.yaml
│   │   │   └── operator-utils.example.io_templatedenforcingcrds.yaml
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches/
│   │       ├── cainjection_in_enforcingcrds.yaml
│   │       ├── cainjection_in_enforcingpatches.yaml
│   │       ├── cainjection_in_mycrds.yaml
│   │       ├── cainjection_in_templatedenforcingcrds.yaml
│   │       ├── webhook_in_enforcingcrds.yaml
│   │       ├── webhook_in_enforcingpatches.yaml
│   │       ├── webhook_in_mycrds.yaml
│   │       └── webhook_in_templatedenforcingcrds.yaml
│   ├── default/
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── helmchart/
│   │   ├── .helmignore
│   │   ├── Chart.yaml.tpl
│   │   ├── kustomization.yaml
│   │   ├── templates/
│   │   │   ├── _helpers.tpl
│   │   │   └── manager.yaml
│   │   └── values.yaml.tpl
│   ├── local-development/
│   │   └── kustomization.yaml
│   ├── manager/
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── manifests/
│   │   ├── bases/
│   │   │   └── operator-utils.clusterserviceversion.yaml
│   │   └── kustomization.yaml
│   ├── prometheus/
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── monitor.yaml
│   ├── rbac/
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── enforcingcrd_editor_role.yaml
│   │   ├── enforcingcrd_viewer_role.yaml
│   │   ├── enforcingpatch_editor_role.yaml
│   │   ├── enforcingpatch_viewer_role.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── mycrd_editor_role.yaml
│   │   ├── mycrd_viewer_role.yaml
│   │   ├── role.yaml
│   │   ├── role_binding.yaml
│   │   ├── templatedenforcingcrd_editor_role.yaml
│   │   └── templatedenforcingcrd_viewer_role.yaml
│   ├── samples/
│   │   ├── kustomization.yaml
│   │   ├── operator-utils_v1alpha1_enforcingcrd.yaml
│   │   ├── operator-utils_v1alpha1_enforcingpatch.yaml
│   │   ├── operator-utils_v1alpha1_mycrd.yaml
│   │   └── operator-utils_v1alpha1_templatedenforcingcrd.yaml
│   ├── scorecard/
│   │   ├── bases/
│   │   │   └── config.yaml
│   │   ├── kustomization.yaml
│   │   └── patches/
│   │       ├── basic.config.yaml
│   │       └── olm.config.yaml
│   └── webhook/
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── controllers/
│   ├── enforcingcrd_controller.go
│   ├── enforcingpatch_controller.go
│   ├── mycrd_controller.go
│   ├── suite_test.go
│   └── templatedenforcingcrd_controller.go
├── go.mod
├── go.sum
├── hack/
│   └── boilerplate.go.txt
├── main.go
├── pkg/
│   └── util/
│       ├── apis/
│       │   ├── conditions.go
│       │   └── key.go
│       ├── crud/
│       │   └── crudutils.go
│       ├── discoveryclient/
│       │   └── discoveryclientutils.go
│       ├── dynamicclient/
│       │   └── dynamicclientutils.go
│       ├── finalizer.go
│       ├── lockedresourcecontroller/
│       │   ├── enforcing-reconciler.go
│       │   ├── locked-resource-manager.go
│       │   ├── lockedpatch/
│       │   │   └── lockedpatch.go
│       │   ├── lockedresource/
│       │   │   ├── lockedresource.go
│       │   │   ├── lockedresourceset/
│       │   │   │   ├── lockedresourceset.go
│       │   │   │   ├── lockedresourceset_bench_test.go
│       │   │   │   └── lockedresourceset_test.go
│       │   │   └── patch.go
│       │   ├── patch-reconciler.go
│       │   └── resource-reconciler.go
│       ├── owner.go
│       ├── predicates.go
│       ├── reconciler.go
│       ├── stoppablemanager/
│       │   └── stoppable-manager.go
│       └── templates/
│           ├── advanced-funcmap.go
│           └── templates.go
├── test/
│   ├── enforcing-patch-multiple-cluster-level.yaml
│   ├── enforcing-patch-multiple.yaml
│   ├── enforcing-patch.yaml
│   ├── enforcing_cr.yaml
│   ├── failing-enforcing_cr.yaml
│   ├── mycrd_cr.yaml
│   └── templatedenforcing_cr.yaml
└── testbin/
    └── setup-envtest.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/pr.yaml
================================================
name: pull request
on:
  pull_request:
    branches:
      - master
      - main

jobs:
  setup:
    runs-on: ubuntu-latest
    name: setup
    env:
      BUILD_PLATFORMS: "linux/amd64,linux/arm64,linux/ppc64le,linux/s390x"
      GO_VERSION: "~1.21"
    steps:
      - name: Setting Workflow Variables
        id: set-variables
        run: |
          echo "::set-output name=repository_name::$(basename $GITHUB_REPOSITORY)"
          echo "::set-output name=bin_dir::$(pwd)/bin"
          
          # Create Distribution Matrix
          echo "::set-output name=dist_matrix::$(echo -n "${{ env.BUILD_PLATFORMS }}" | jq -csR '. | split(",")')"

          # Set versions based on presence of tag
          if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
            TAG="${GITHUB_REF/refs\/tags\//}"
            echo "::set-output name=tag_event::true"
            echo "::set-output name=operator_version::$TAG"
          else
            echo "::set-output name=tag_event::false"
            echo "::set-output name=operator_version::$DEFAULT_OPERATOR_VERSION"
          fi

      - name: Build Go Cache Paths
        id: go-cache-paths
        run: |
          echo "::set-output name=go-build::$(go env GOCACHE)"
          echo "::set-output name=go-mod::$(go env GOMODCACHE)"

      - name: Set up Go 1.x
        uses: actions/setup-go@v1
        with:
          go-version: ${{ inputs.GO_VERSION }}

      - name: Check out code
        uses: actions/checkout@v2

      - name: Go Build Cache
        uses: actions/cache@v2
        with:
          path: ${{ steps.go-cache-paths.outputs.go-build }}
          key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}

      - name: Go Mod Cache
        uses: actions/cache@v2
        with:
          path: ${{ steps.go-cache-paths.outputs.go-mod }}
          key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}

      - name: Go Dependencies
        run: go mod download

      - name: Download Binaries
        env:
          OPERATOR_SDK_VERSION: ${{ inputs.OPERATOR_SDK_VERSION }}
        run: |
          # Create Binary Directory
          mkdir -p ${{ steps.set-variables.outputs.bin_dir }}
          # Operator SDK
          curl -L -o ${{ steps.set-variables.outputs.bin_dir }}/operator-sdk https://github.com/operator-framework/operator-sdk/releases/download/${{ env.OPERATOR_SDK_VERSION }}/operator-sdk_linux_amd64
          # Controller-gen
          make controller-gen
          # Kustomize
          make kustomize

      - name: Upload Support Binaries
        uses: actions/upload-artifact@v2
        with:
          name: support-binaries
          path: ${{ steps.set-variables.outputs.bin_dir }}

    outputs:
      repository_name: ${{ steps.set-variables.outputs.repository_name }}
      bin_dir: ${{ steps.set-variables.outputs.bin_dir }}
      go_build: ${{ steps.go-cache-paths.outputs.go-build }}
      go_mod: ${{ steps.go-cache-paths.outputs.go-mod }}
      tag_event: ${{ steps.set-variables.outputs.tag_event }}
      dist_matrix: ${{ steps.set-variables.outputs.dist_matrix }}

  build-operator:
    runs-on: ubuntu-latest
    name: build-operator
    needs: ["setup"]
    strategy:
      matrix:
        platform: ${{ fromJson(needs.setup.outputs.dist_matrix) }}
    env:
      REPOSITORY_NAME: ${{ needs.setup.outputs.repository_name }}
    steps:
      - name: Set up Go 1.x
        uses: actions/setup-go@v1
        with:
          go-version: ${{ inputs.GO_VERSION }}

      - name: Check out code
        uses: actions/checkout@v2

      - name: Go Build Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_build }}
          key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}

      - name: Go Mod Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_mod }}
          key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}

      - name: Download Support Binaries
        uses: actions/download-artifact@v2
        with:
          name: support-binaries
          path: ${{ needs.setup.outputs.bin_dir }}

      - name: Prepare Build Step
        id: setup-build-step
        run: |
          # Setup Path
          echo "${{ needs.setup.outputs.bin_dir }}" >> $GITHUB_PATH
          # Make Binaries Executable
          chmod +x ${{ needs.setup.outputs.bin_dir }}/*
          # Configure Platform Variables
          echo "::set-output name=platform_os::$(echo ${{ matrix.platform }} |  cut -d/ -f1)"
          echo "::set-output name=platform_arch::$(echo ${{ matrix.platform }} |  cut -d/ -f2)"

      - name: Download Dependencies
        shell: bash
        run: |
          make generate
          make fmt
          make vet

      - name: build code
        shell: bash
        env:
          VERSION: latest
          GOOS: ${{ steps.setup-build-step.outputs.platform_os }}
          GOARCH: ${{ steps.setup-build-step.outputs.platform_arch }}
        run: make

  test-operator:
    runs-on: ubuntu-latest
    name: test-operator
    needs: ["setup"]
    env:
      REPOSITORY_NAME: ${{ needs.setup.outputs.repository_name }}
    steps:
      - name: Set up Go 1.x
        uses: actions/setup-go@v1
        with:
          go-version: ${{ inputs.GO_VERSION }}

      - name: Check out code
        uses: actions/checkout@v2

      - name: Go Build Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_build }}
          key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}

      - name: Go Mod Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_mod }}
          key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}

      - name: Download Binaries
        uses: actions/download-artifact@v2
        with:
          name: support-binaries
          path: ${{ needs.setup.outputs.bin_dir }}

      - name: Prepare Build Step
        id: setup-build-step
        run: |
          # Setup Path
          echo "${{ needs.setup.outputs.bin_dir }}" >> $GITHUB_PATH
          # Make Binaries Executable
          chmod +x ${{ needs.setup.outputs.bin_dir }}/*

      - name: Run unit tests
        shell: bash
        run: make test


================================================
FILE: .github/workflows/push.yaml
================================================
name: push
on:
  push:
    branches:
      - main
      - master
    tags:
      - v*

jobs:
  setup:
    runs-on: ubuntu-latest
    name: setup
    env:
      BUILD_PLATFORMS: "linux/amd64,linux/arm64,linux/ppc64le,linux/s390x"
      GO_VERSION: "~1.21"
    steps:
      - name: Setting Workflow Variables
        id: set-variables
        run: |
          echo "::set-output name=repository_name::$(basename $GITHUB_REPOSITORY)"
          echo "::set-output name=bin_dir::$(pwd)/bin"
          
          # Create Distribution Matrix
          echo "::set-output name=dist_matrix::$(echo -n "${{ env.BUILD_PLATFORMS }}" | jq -csR '. | split(",")')"

          # Set versions based on presence of tag
          if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
            TAG="${GITHUB_REF/refs\/tags\//}"
            echo "::set-output name=tag_event::true"
            echo "::set-output name=operator_version::$TAG"
          else
            echo "::set-output name=tag_event::false"
            echo "::set-output name=operator_version::$DEFAULT_OPERATOR_VERSION"
          fi

      - name: Build Go Cache Paths
        id: go-cache-paths
        run: |
          echo "::set-output name=go-build::$(go env GOCACHE)"
          echo "::set-output name=go-mod::$(go env GOMODCACHE)"

      - name: Set up Go 1.x
        uses: actions/setup-go@v1
        with:
          go-version: ${{ inputs.GO_VERSION }}

      - name: Check out code
        uses: actions/checkout@v2

      - name: Go Build Cache
        uses: actions/cache@v2
        with:
          path: ${{ steps.go-cache-paths.outputs.go-build }}
          key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}

      - name: Go Mod Cache
        uses: actions/cache@v2
        with:
          path: ${{ steps.go-cache-paths.outputs.go-mod }}
          key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}

      - name: Go Dependencies
        run: go mod download

      - name: Download Binaries
        env:
          OPERATOR_SDK_VERSION: ${{ inputs.OPERATOR_SDK_VERSION }}
        run: |
          # Create Binary Directory
          mkdir -p ${{ steps.set-variables.outputs.bin_dir }}
          # Operator SDK
          curl -L -o ${{ steps.set-variables.outputs.bin_dir }}/operator-sdk https://github.com/operator-framework/operator-sdk/releases/download/${{ env.OPERATOR_SDK_VERSION }}/operator-sdk_linux_amd64
          # Controller-gen
          make controller-gen
          # Kustomize
          make kustomize

      - name: Upload Support Binaries
        uses: actions/upload-artifact@v2
        with:
          name: support-binaries
          path: ${{ steps.set-variables.outputs.bin_dir }}

    outputs:
      repository_name: ${{ steps.set-variables.outputs.repository_name }}
      bin_dir: ${{ steps.set-variables.outputs.bin_dir }}
      go_build: ${{ steps.go-cache-paths.outputs.go-build }}
      go_mod: ${{ steps.go-cache-paths.outputs.go-mod }}
      tag_event: ${{ steps.set-variables.outputs.tag_event }}
      dist_matrix: ${{ steps.set-variables.outputs.dist_matrix }}

  build-operator:
    runs-on: ubuntu-latest
    name: build-operator
    needs: ["setup"]
    strategy:
      matrix:
        platform: ${{ fromJson(needs.setup.outputs.dist_matrix) }}
    env:
      REPOSITORY_NAME: ${{ needs.setup.outputs.repository_name }}
    steps:
      - name: Set up Go 1.x
        uses: actions/setup-go@v1
        with:
          go-version: ${{ inputs.GO_VERSION }}

      - name: Check out code
        uses: actions/checkout@v2

      - name: Go Build Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_build }}
          key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}

      - name: Go Mod Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_mod }}
          key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}

      - name: Download Support Binaries
        uses: actions/download-artifact@v2
        with:
          name: support-binaries
          path: ${{ needs.setup.outputs.bin_dir }}

      - name: Prepare Build Step
        id: setup-build-step
        run: |
          # Setup Path
          echo "${{ needs.setup.outputs.bin_dir }}" >> $GITHUB_PATH
          # Make Binaries Executable
          chmod +x ${{ needs.setup.outputs.bin_dir }}/*
          # Configure Platform Variables
          echo "::set-output name=platform_os::$(echo ${{ matrix.platform }} |  cut -d/ -f1)"
          echo "::set-output name=platform_arch::$(echo ${{ matrix.platform }} |  cut -d/ -f2)"

      - name: Download Dependencies
        shell: bash
        run: |
          make generate
          make fmt
          make vet

      - name: build code
        shell: bash
        env:
          VERSION: latest
          GOOS: ${{ steps.setup-build-step.outputs.platform_os }}
          GOARCH: ${{ steps.setup-build-step.outputs.platform_arch }}
        run: make

  test-operator:
    runs-on: ubuntu-latest
    name: test-operator
    needs: ["setup"]
    env:
      REPOSITORY_NAME: ${{ needs.setup.outputs.repository_name }}
    steps:
      - name: Set up Go 1.x
        uses: actions/setup-go@v1
        with:
          go-version: ${{ inputs.GO_VERSION }}

      - name: Check out code
        uses: actions/checkout@v2

      - name: Go Build Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_build }}
          key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}

      - name: Go Mod Cache
        uses: actions/cache@v2
        with:
          path: ${{ needs.setup.outputs.go_mod }}
          key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}

      - name: Download Binaries
        uses: actions/download-artifact@v2
        with:
          name: support-binaries
          path: ${{ needs.setup.outputs.bin_dir }}

      - name: Prepare Build Step
        id: setup-build-step
        run: |
          # Setup Path
          echo "${{ needs.setup.outputs.bin_dir }}" >> $GITHUB_PATH
          # Make Binaries Executable
          chmod +x ${{ needs.setup.outputs.bin_dir }}/*

      - name: Run unit tests
        shell: bash
        run: make test

  github-release:
    runs-on: ubuntu-latest
    name: github-release
    if: ${{ needs.setup.outputs.tag_event == 'true' }}
    needs:
      [
        "setup",
        "test-operator",
        "build-operator",
      ]
    steps:
      - name: Check out code
        uses: actions/checkout@v2

      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          generate_release_notes: true
          draft: false
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================

# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Kubernetes Generated files - skip generated files, except for vendored files

!vendor/**/zz_generated.*

# editor and IDE paraphernalia
.idea
*.swp
*.swo
*~

bundle/
bundle.Dockerfile

================================================
FILE: Dockerfile
================================================
# Build the manager binary
FROM golang:1.18 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/
COPY pkg/ pkg/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532

ENTRYPOINT ["/manager"]


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: Makefile
================================================
# VERSION defines the project version for the bundle.
# Update this value when you upgrade the version of your project.
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.0.1

# CHANNELS define the bundle channels used in the bundle.
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
# To re-generate a bundle for other specific channels without changing the standard setup, you can:
# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable)
# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable")
ifneq ($(origin CHANNELS), undefined)
BUNDLE_CHANNELS := --channels=$(CHANNELS)
endif

# DEFAULT_CHANNEL defines the default channel used in the bundle.
# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable")
# To re-generate a bundle for any other default channel without changing the default setup, you can:
# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable)
# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable")
ifneq ($(origin DEFAULT_CHANNEL), undefined)
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
endif
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)

# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images.
# This variable is used to construct full image tags for bundle and catalog images.
#
# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both
# example.com/memcached-operator-bundle:$VERSION and example.com/memcached-operator-catalog:$VERSION.
IMAGE_TAG_BASE ?= example.com/memcached-operator

# BUNDLE_IMG defines the image:tag used for the bundle.
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)

# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command
BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)

# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests
# You can enable this value if you would like to use SHA Based Digests
# To enable set flag to true
USE_IMAGE_DIGESTS ?= false
ifeq ($(USE_IMAGE_DIGESTS), true)
	BUNDLE_GEN_FLAGS += --use-image-digests
endif

# Image URL to use all building/pushing image targets
IMG ?= controller:latest
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.24.1

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

# Setting SHELL to bash allows bash commands to be executed by recipes.
# This is a requirement for 'setup-envtest.sh' in the test target.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

CHART_REPO_URL ?= http://example.com
HELM_REPO_DEST ?= /tmp/gh-pages

.PHONY: all
all: build

##@ General

# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk commands is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

.PHONY: help
help: ## Display this help.
	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Development

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
	$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
	$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

.PHONY: fmt
fmt: ## Run go fmt against code.
	go fmt ./...

.PHONY: vet
vet: ## Run go vet against code.
	go vet ./...

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
	KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out

##@ Build

.PHONY: build
build: generate fmt vet ## Build manager binary.
	go build -o bin/manager main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
	go run ./main.go

.PHONY: docker-build
docker-build: test ## Build docker image with the manager.
	docker build -t ${IMG} .

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
	docker push ${IMG}

##@ Deployment

ifndef ignore-not-found
  ignore-not-found = false
endif

.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
	$(KUSTOMIZE) build config/crd | kubectl apply -f -

.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
	$(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
	cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
	$(KUSTOMIZE) build config/default | kubectl apply -f -

.PHONY: undeploy
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
	$(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f -

##@ Build Dependencies

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
	mkdir -p $(LOCALBIN)

## Tool Binaries
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest

## Tool Versions
KUSTOMIZE_VERSION ?= v3.8.7
CONTROLLER_TOOLS_VERSION ?= v0.9.0

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
	curl -s $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN)

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
	GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)

.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
	GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest

.PHONY: bundle
bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files.
	operator-sdk generate kustomize manifests --interactive=false -q
	cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
	$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS)
	operator-sdk bundle validate ./bundle

.PHONY: bundle-build
bundle-build: ## Build the bundle image.
	docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .

.PHONY: bundle-push
bundle-push: ## Push the bundle image.
	$(MAKE) docker-push IMG=$(BUNDLE_IMG)

.PHONY: opm
OPM = ./bin/opm
opm: ## Download opm locally if necessary.
ifeq (,$(wildcard $(OPM)))
ifeq (,$(shell which opm 2>/dev/null))
	@{ \
	set -e ;\
	mkdir -p $(dir $(OPM)) ;\
	OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
	curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\
	chmod +x $(OPM) ;\
	}
else
OPM = $(shell which opm)
endif
endif

# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0).
# These images MUST exist in a registry and be pull-able.
BUNDLE_IMGS ?= $(BUNDLE_IMG)

# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0).
CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION)

# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image.
ifneq ($(origin CATALOG_BASE_IMG), undefined)
FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG)
endif

# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'.
# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see:
# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator
.PHONY: catalog-build
catalog-build: opm ## Build a catalog image.
	$(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT)

# Push the catalog image.
.PHONY: catalog-push
catalog-push: ## Push a catalog image.
	$(MAKE) docker-push IMG=$(CATALOG_IMG)

# Generate helm chart
.PHONY: kustomize
helmchart: kustomize
	mkdir -p ./charts/${OPERATOR_NAME}/templates
	cp ./config/helmchart/templates/* ./charts/${OPERATOR_NAME}/templates
	$(KUSTOMIZE) build ./config/helmchart | sed 's/release-namespace/{{.Release.Namespace}}/' > ./charts/${OPERATOR_NAME}/templates/rbac.yaml
	version=${VERSION} envsubst < ./config/helmchart/Chart.yaml.tpl  > ./charts/${OPERATOR_NAME}/Chart.yaml
	version=${VERSION} image_repo=$${IMG%:*} envsubst < ./config/helmchart/values.yaml.tpl  > ./charts/${OPERATOR_NAME}/values.yaml
	helm lint ./charts/${OPERATOR_NAME}	

.PHONY: helmchart
helmchart-repo: helmchart
	mkdir -p ${HELM_REPO_DEST}/${OPERATOR_NAME}
	helm package -d ${HELM_REPO_DEST}/${OPERATOR_NAME} ./charts/${OPERATOR_NAME}
	helm repo index --url ${CHART_REPO_URL} ${HELM_REPO_DEST}

.PHONY: helmchart-repo
helmchart-repo-push: helmchart-repo	
	git -C ${HELM_REPO_DEST} add .
	git -C ${HELM_REPO_DEST} status
	git -C ${HELM_REPO_DEST} commit -m "Release ${VERSION}"
	git -C ${HELM_REPO_DEST} push origin "gh-pages"	


================================================
FILE: PROJECT
================================================
domain: example.io
layout:
- go.kubebuilder.io/v3
projectName: operator-utils
repo: github.com/redhat-cop/operator-utils
resources:
- domain: example.io
  group: operator-utils
  kind: MyCRD
  path: github.com/redhat-cop/operator-utils/api/v1alpha1
  version: v1alpha1
- domain: example.io
  group: operator-utils
  kind: EnforcingCRD
  path: github.com/redhat-cop/operator-utils/api/v1alpha1
  version: v1alpha1
- domain: example.io
  group: operator-utils
  kind: EnforcingPatch
  path: github.com/redhat-cop/operator-utils/api/v1alpha1
  version: v1alpha1
- domain: example.io
  group: operator-utils
  kind: EnforcingPatch
  path: github.com/redhat-cop/operator-utils/api/v1alpha1
  version: v1alpha1       
version: "3"
plugins:
  manifests.sdk.operatorframework.io/v2: {}
  scorecard.sdk.operatorframework.io/v2: {}


================================================
FILE: README.md
================================================
# Operator Utility Library

![build status](https://github.com/redhat-cop/operator-utils/workflows/push/badge.svg)
[![GoDoc reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/redhat-cop/operator-utils)
[![Go Report Card](https://goreportcard.com/badge/github.com/redhat-cop/operator-utils)](https://goreportcard.com/report/github.com/redhat-cop/operator-utils)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/redhat-cop/operator-utils)

This library layers on top of the Operator SDK and with the objective of helping writing better and more consistent operators.

*NOTICE* versions of this library up to `v0.3.7` are compatible with [operator-sdk](https://github.com/operator-framework/operator-sdk) `0.x`, starting from version v0.4.0 this library will be compatible only with [operator-sdk](https://github.com/operator-framework/operator-sdk) 1.x.

## Scope of this library

This library covers three main areas:

1. [Utility Methods](#Utility-Methods) Utility methods that are callable by any operator.
2. [Idempotent methods](#Idempotent-Methods-to-Manipulate-Resources) to manipulate resources and arrays of resources
3. [Basic operator lifecycle](#Basic-Operator-Lifecycle-Management) needs (validation, initialization, status and error management, finalization)
4. [Enforcing resources operator support](#Enforcing-Resource-Operator-Support). For those operators which calculate a set of resources that need to exist and then enforce them, generalized support for the enforcing phase is provided.

## Utility Methods

Prior to version v1.3.x the general philosophy of this library was that new operator would inherit from `ReconcilerBase` and in doing so they would have access to a bunch of utility methods.
With release v1.3.0 a new approach is available. Utility methods are callable by any operator without having to inherit. This makes it easier to use this library and does not conflict with autogenerate code from `kube-builder` and `operator-sdk`.
Most of the Utility methods receive a context.Context parameter. Normally this context must be initialized with a `logr.Logger` and a `rest.Config`. Some utility methods may require more, see each individual documentation.

Utility methods are currently organized in the following folders:

1. crud: idempotent create/update/delete functions.
2. discoveryclient: methods related to the discovery client, typically used to load `apiResource` objects.
3. dynamicclient: methods related to building client based on object whose type is not known at compile time.
4. templates: utility methods for dealing with templates whose output is an object or a list of objects.

## Idempotent Methods to Manipulate Resources

The following idempotent methods are provided (and their corresponding array version):

1. createIfNotExists
2. createOrUpdate
3. deleteIfExists

Also there are utility methods to manage finalizers, test ownership and process templates of resources.

## Basic Operator Lifecycle Management

---

Note

This part of the library is largely deprecated. For initialization and defaulting a MutatingWebHook should be used. For validation a Validating WebHook should be used.
The part regarding the finalization is still relevant.

---

To get started with this library do the following:

Change your reconciler initialization as exemplified below to add a set of utility methods to it

```go
import "github.com/redhat-cop/operator-utils/pkg/util"

...
type MyReconciler struct {
  util.ReconcilerBase
  Log logr.Logger
  ... other optional fields ...
}
```

in main.go change like this

```go
  if err = (&controllers.MyReconciler{
    ReconcilerBase: util.NewReconcilerBase(mgr.GetClient(), mgr.GetScheme(), mgr.GetConfig(), mgr.GetEventRecorderFor("My_controller"), mgr.GetAPIReader()),
    Log:            ctrl.Log.WithName("controllers").WithName("My"),
  }).SetupWithManager(mgr); err != nil {
    setupLog.Error(err, "unable to create controller", "controller", "My")
    os.Exit(1)
  }
```

Also make sure to create the manager with `configmap` as the lease option for leader election:

```go
  mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
    Scheme:                     scheme,
    MetricsBindAddress:         metricsAddr,
    Port:                       9443,
    LeaderElection:             enableLeaderElection,
    LeaderElectionID:           "dcb036b8.redhat.io",
    LeaderElectionResourceLock: "configmaps",
  })
```  

If you want status management, add this to your CRD:

```go
  // +patchMergeKey=type
  // +patchStrategy=merge
  // +listType=map
  // +listMapKey=type
  Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

func (m *MyCRD) GetConditions() []metav1.Condition {
  return m.Status.Conditions
}

func (m *MyCRD) SetConditions(conditions []metav1.Condition) {
  m.Status.Conditions = conditions
}
```

At this point your controller is able to leverage the utility methods of this library:

1. [managing CR validation](#managing-cr-validation)
2. [managing CR initialization](#managing-cr-initialization)
3. [managing status and error conditions](#managing-status-and-error-conditions)
4. [managing CR finalization](#managing-cr-finalization)
5. high-level object manipulation functions such as:
   - createOrUpdate, createIfNotExists, deleteIfExists
   - same functions on an array of objects
   - go template processing of objects

A full example is provided [here](./controllers/mycrd_controller.go)

### Managing CR validation

To enable CR validation add this to your controller:

```go
if ok, err := r.IsValid(instance); !ok {
 return r.ManageError(ctx, instance, err)
}
```

The implement the following function:

```go
func (r *ReconcileMyCRD) IsValid(obj metav1.Object) (bool, error) {
 mycrd, ok := obj.(*examplev1alpha1.MyCRD)
 ...
}
```

### Managing CR Initialization

To enable CR initialization, add this to your controller:

```go
if ok := r.IsInitialized(instance); !ok {
 err := r.GetClient().Update(context.TODO(), instance)
 if err != nil {
  log.Error(err, "unable to update instance", "instance", instance)
  return r.ManageError(ctx, instance, err)
 }
 return reconcile.Result{}, nil
}
```

Then implement the following function:

```go
func (r *ReconcileMyCRD) IsInitialized(obj metav1.Object) bool {
 mycrd, ok := obj.(*examplev1alpha1.MyCRD)
}
```

### Managing Status and Error Conditions

To update the status with success and return from the reconciliation cycle, code the following:

```go
return r.ManageSuccess(ctx, instance)
```

To update the status with failure, record an event and return from the reconciliation cycle, code the following:

```go
return r.ManageError(ctx, instance, err)
```

notice that this function will reschedule a reconciliation cycle with increasingly longer wait time up to six hours.

There are also variants of these calls to allow for requeuing after a given delay.
Requeuing is handy when reconciliation depends on a cluster-external state which is not observable from within the api-server.

```go
return r.ManageErrorWithRequeue(ctx, instance, err, 3*time.Second)
```

```go
return r.ManageSuccessWithRequeue(ctx, instance, 3*time.Second)
```

or simply using the convenience function:

```go
return r.ManageOutcomeWithRequeue(ctx, instance, err, 3*time.Second)
```

which will delegate to the error or success variant depending on `err` being `nil` or not.

### Managing CR Finalization

to enable CR finalization add this to your controller:

```go
if util.IsBeingDeleted(instance) {
 if !util.HasFinalizer(instance, controllerName) {
  return reconcile.Result{}, nil
 }
 err := r.manageCleanUpLogic(instance)
 if err != nil {
  log.Error(err, "unable to delete instance", "instance", instance)
  return r.ManageError(ctx, instance, err)
 }
 util.RemoveFinalizer(instance, controllerName)
 err = r.GetClient().Update(context.TODO(), instance)
 if err != nil {
  log.Error(err, "unable to update instance", "instance", instance)
  return r.ManageError(ctx, instance, err)
 }
 return reconcile.Result{}, nil
}
```

Then implement this method:

```go
func (r *ReconcileMyCRD) manageCleanUpLogic(mycrd *examplev1alpha1.MyCRD) error {
  ...
}
```

## Support for operators that need to enforce a set of resources to a defined state

Many operators have the following logic:

1. Phase 1: based on the CR and potentially additional status, a set of resources that need to exist is calculated.
2. Phase 2: These resources are then created or updated against the master API.
3. Phase 3: A well written operator also ensures that these resources stay in place and are not accidentally or maliciously changed by third parties.

These phases are of increasing difficulty to implement. It's also true that phase 2 and 3 can be generalized.

Operator-utils offers some scaffolding to assist in writing these kinds of operators.

Similarly to the `BaseReconciler` class, we have a base type to extend called: `EnforcingReconciler`. This class extends from `BaseReconciler`, so you have all the same facilities as above.

When initializing the EnforcingReconciler, one must chose whether watchers will be created at the cluster level or at the namespace level.

- if cluster level is chosen a watch per CR and type defined in it will be created. This will require the operator to have cluster level access.

- if namespace level watchers is chosen a watch per CR, type and namespace will be created. This will minimize the needed permissions, but depending on what the operator needs to do may open a very high number of connections to the API server.

The body of the reconciler function will look something like this:

```golang
validation...
initialization...
(optional) finalization...
Phase1 ... calculate a set of resources to be enforced -> LockedResources

  err = r.UpdateLockedResources(context,instance, lockedResources, ...)
  if err != nil {
    log.Error(err, "unable to update locked resources")
    return r.ManageError(ctx, instance, err)
 }

  return r.ManageSuccess(ctx, instance)
```

this is all you have to do for basic functionality. For more details see the [example](pkg/controller/apis/enforcingcrd/enforcingcrd_controller.go)
the EnforcingReconciler will do the following:

1. restore the resources to the desired stated if the are changed. Notice that you can exclude paths from being considered when deciding whether to restore a resource. As set of JSON Path can be passed together with the LockedResource. It is recommended to set these paths:
    1. `.metadata`
    2. `.status`

2. restore resources when they are deleted.

The `UpdateLockedResources` will validate the input as follows:

1. the passed resource must be defined in the current apiserver
2. the passed resource must be syntactically compliant with the OpenAPI definition of the resource defined in the server.
3. if the passed resource is namespaced, the namespace field must be initialized.

The finalization method will look like this:

```golang
func (r *ReconcileEnforcingCRD) manageCleanUpLogic(instance *examplev1alpha1.EnforcingCRD) error {
  err := r.Terminate(instance, true)
  if err != nil {
    log.Error(err, "unable to terminate enforcing reconciler for", "instance", instance)
    return err
  }
  ... additional finalization logic ...
  return nil
}
```

Convenience methods are also available for when resources are templated. See the [templatedenforcingcrd](./pkgcontroller/templatedenforcingcrd/templatedenforcingcrd_controller.go) controller as an example.

## Support for operators that need to enforce a set of patches

For similar reasons stated in the previous paragraphs, operators might need to enforce patches.
A patch modifies an object created by another entity. Because in this case the CR does not own the to-be-modified object a patch must be enforced against changes made on it.
One must be careful not to create circular situations where an operator deletes the patch and this operator recreates the patch.
In some situations, a patch must be parametric on some state of the cluster. For this reason, it's possible to monitor source objects that will be used as parameters to calculate the patch.

A patch is defined as follows:

```golang
type LockedPatch struct { 
  Name             string                           `json:"name,omitempty"`
  SourceObjectRefs []utilsapi.SourceObjectReference `json:"sourceObjectRefs,omitempty"`
  TargetObjectRef  utilsapi.TargetObjectReference   `json:"targetObjectRef,omitempty"`
  PatchType        types.PatchType                  `json:"patchType,omitempty"`
  PatchTemplate    string                           `json:"patchTemplate,omitempty"`
  Template         template.Template                `json:"-"`
}
```

the targetObjectRef and sourceObjectRefs are watched for changes by the reconciler.

targetObjectRef can select multiple objects, this is the logic

| Namespaced Type | Namespace | Name | Selection type |
| --- | --- | --- | --- |
| yes | null | null | multiple selection across namespaces |
| yes | null | not null | multiple selection across namespaces where the name corresponds to the passed name |
| yes | not null | null | multiple selection within a namespace |
| yes | not null | not nul | single selection |
| no | N/A | null | multiple selection  |
| no | N/A | not null | single selection |

Selection can be further narrowed down by filtering by labels and/or annotations. The patch will be applied to all of the selected instances.

Name and Namespace of sourceRefObjects are interpreted as golang templates with the current target instance and the only parameter. This allows to select different source object for each target object.

The relevant part of the operator code would look like this:

```golang
validation...
initialization...
Phase1 ... calculate a set of patches to be enforced -> LockedPatches

  err = r.UpdateLockedResources(context, instance, ..., lockedPatches...)
  if err != nil {
    log.Error(err, "unable to update locked resources")
    return r.ManageError(ctx, instance, err)
 }

  return r.ManageSuccess(ctx, instance)
```

The `UpdateLockedResources` will validate the input as follows:

1. the passed patch target/source `ObjectRef` resource must be defined in the current apiserver
2. if the passed patch target/source `ObjectRef` resources are namespaced the corresponding namespace field must be initialized.
3. the ID must have a not null and unique value in the array of the passed patches.

Patches cannot be undone so there is no need to manage a finalizer.

[Here](./pkg/controller/enforcingpatch/enforcingpatch_controller.go) you can find an example of how to implement an operator with this the ability to enforce patches.

## Support for operators that need dynamic creation of locked resources using templates

Operators may also need to leverage locked resources created dynamically through templates. This can be done using [go templates](https://golang.org/pkg/text/template/) and leveraging the `GetLockedResourcesFromTemplates` function.

```golang
lockedResources, err := r.GetLockedResourcesFromTemplates(templates..., params...)
if err != nil {
  log.Error(err, "unable to process templates with param")
  return err
}
```

The `GetLockedResourcesFromTemplates` will validate the input as follows:

1. check that the passed template is valid
2. format the template using the properties of the passed object in the params parameter
3. create an array of `LockedResource` objects based on parsed template

The example below shows how templating can be used to reference the name of the resource passed as the parameter and use it as a property in the creation of the `LockedResource`.

```golang
objectTemplate: |
  apiVersion: v1
  kind: Namespace
  metadata:
    name: {{ .Name }}
```

This functionality can leverage advanced features of go templating, such as loops, to generate more than one object following a set pattern. The below example will create an array of namespace `LockedResources` using the title of any key where the associated value matches the text *devteam* in the key/value pair of the `Labels` property of the resource passed in the params parameter.

```golang
objectTemplate: |
  {{range $key, $value := $.Labels}}
    {{if eq $value "devteam"}}
      - apiVersion: v1
        kind: Namespace
        metadata:
          name: {{ $key }}
    {{end}}
  {{end}}
```

## Support for operators that need advanced templating functionality

Operators may need to utilize advanced templating functions not found in the base go templating library. This advanced template functionality matches the same available in the popular k8s management tool [Helm](https://helm.sh/). `LockedPatch` templates uses this functionality by default. To utilize these features when using `LockedResources` the following function is required,

```golang
lockedResources, err := r.GetLockedResourcesFromTemplatesWithRestConfig(templates..., rest.Config..., params...)
if err != nil {
  log.Error(err, "unable to process templates with param")
  return err
}
```  

## Deployment

### Deploying with Helm

Here are the instructions to install the latest release with Helm.

```shell
oc new-project operator-utils
helm repo add operator-utils https://redhat-cop.github.io/operator-utils
helm repo update
helm install operator-utils operator-utils/operator-utils
```

This can later be updated with the following commands:

```shell
helm repo update
helm upgrade operator-utils operator-utils/operator-utils
```

## Development

## Running the operator locally

```shell
make install
oc new-project operator-utils-operator-local
kustomize build ./config/local-development | oc apply -f - -n operator-utils-operator-local
export token=$(oc serviceaccounts get-token 'operator-utils-operator-controller-manager' -n operator-utils-operator-local)
oc login --token ${token}
make run ENABLE_WEBHOOKS=false
```

### testing

Patches

```shell
oc new-project patch-test
oc create sa test -n patch-test
oc adm policy add-cluster-role-to-user cluster-admin -z default -n patch-test
oc apply -f ./test/enforcing-patch.yaml -n patch-test
oc apply -f ./test/enforcing-patch-multiple.yaml -n patch-test
oc apply -f ./test/enforcing-patch-multiple-cluster-level.yaml -n patch-test
```

## Building/Pushing the operator image

```shell
export repo=raffaelespazzoli #replace with yours
docker login quay.io/$repo
make docker-build IMG=quay.io/$repo/operator-utils:latest
make docker-push IMG=quay.io/$repo/operator-utils:latest
```

## Deploy to OLM via bundle

```shell
make manifests
make bundle IMG=quay.io/$repo/operator-utils:latest
operator-sdk bundle validate ./bundle --select-optional name=operatorhub
make bundle-build BUNDLE_IMG=quay.io/$repo/operator-utils-bundle:latest
docker push quay.io/$repo/operator-utils-bundle:latest
operator-sdk bundle validate quay.io/$repo/operator-utils-bundle:latest --select-optional name=operatorhub
oc new-project operator-utils
oc label namespace operator-utils openshift.io/cluster-monitoring="true"
operator-sdk cleanup operator-utils -n operator-utils
operator-sdk run bundle --install-mode AllNamespaces -n operator-utils quay.io/$repo/operator-utils-bundle:latest
```

## Releasing

```shell
git tag -a "<tagname>" -m "<commit message>"
git push upstream <tagname>
```

If you need to remove a release:

```shell
git tag -d <tagname>
git push upstream --delete <tagname>
```

If you need to "move" a release to the current main

```shell
git tag -f <tagname>
git push upstream -f <tagname>
```

### Cleaning up

```shell
operator-sdk cleanup operator-utils -n operator-utils
oc delete operatorgroup operator-sdk-og
oc delete catalogsource operator-utils-catalog
```


================================================
FILE: api/v1alpha1/enforcingcrd_types.go
================================================
/*


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"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// EnforcingCRDSpec defines the desired state of EnforcingCRD
type EnforcingCRDSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
	// Resources is a list of resource manifests that should be locked into the specified configuration
	// +kubebuilder:validation:Optional
	// +listType=atomic
	Resources []LockedResource `json:"resources,omitempty"`
}

// EnforcingCRDStatus defines the observed state of EnforcingCRD
type EnforcingCRDStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
	// +kubebuilder:validation:Optional
	EnforcingReconcileStatus `json:",inline,omitempty"`
}

func (m *EnforcingCRD) GetEnforcingReconcileStatus() EnforcingReconcileStatus {
	return m.Status.EnforcingReconcileStatus
}

func (m *EnforcingCRD) SetEnforcingReconcileStatus(reconcileStatus EnforcingReconcileStatus) {
	m.Status.EnforcingReconcileStatus = reconcileStatus
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// EnforcingCRD is the Schema for the enforcingcrds API
type EnforcingCRD struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   EnforcingCRDSpec   `json:"spec,omitempty"`
	Status EnforcingCRDStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// EnforcingCRDList contains a list of EnforcingCRD
type EnforcingCRDList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []EnforcingCRD `json:"items"`
}

func init() {
	SchemeBuilder.Register(&EnforcingCRD{}, &EnforcingCRDList{})
}


================================================
FILE: api/v1alpha1/enforcingpatch_types.go
================================================
/*


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"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// EnforcingPatchSpec defines the desired state of EnforcingPatch
type EnforcingPatchSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html

	// Patches is a list of pacthes that should be encforced at runtime.
	// +kubebuilder:validation:Optional
	Patches map[string]PatchSpec `json:"patches,omitempty"`
}

// EnforcingPatchStatus defines the observed state of EnforcingPatch
type EnforcingPatchStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
	EnforcingReconcileStatus `json:",inline,omitempty"`
}

func (m *EnforcingPatch) GetEnforcingReconcileStatus() EnforcingReconcileStatus {
	return m.Status.EnforcingReconcileStatus
}

func (m *EnforcingPatch) SetEnforcingReconcileStatus(reconcileStatus EnforcingReconcileStatus) {
	m.Status.EnforcingReconcileStatus = reconcileStatus
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// EnforcingPatch is the Schema for the enforcingpatches API
type EnforcingPatch struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   EnforcingPatchSpec   `json:"spec,omitempty"`
	Status EnforcingPatchStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// EnforcingPatchList contains a list of EnforcingPatch
type EnforcingPatchList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []EnforcingPatch `json:"items"`
}

func init() {
	SchemeBuilder.Register(&EnforcingPatch{}, &EnforcingPatchList{})
}


================================================
FILE: api/v1alpha1/enforcingreconcilerstatus.go
================================================
package v1alpha1

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// +listType=map
// +listMapKey=type
type Conditions []metav1.Condition

// +mapType=granular
type ConditionMap map[string]Conditions

// EnforcingReconcileStatus represents the status of the last reconcile cycle. It's used to communicate success or failure and the error message
type EnforcingReconcileStatus struct {

	// ReconcileStatus this is the general status of the main reconciler
	// +kubebuilder:validation:Optional
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`

	//LockedResourceStatuses contains the reconcile status for each of the managed resources
	// +kubebuilder:validation:Optional
	LockedResourceStatuses map[string]Conditions `json:"lockedResourceStatuses,omitempty"`

	//LockedResourceStatuses contains the reconcile status for each of the managed resources
	// +kubebuilder:validation:Optional
	LockedPatchStatuses map[string]ConditionMap `json:"lockedPatchStatuses,omitempty"`
}

// EnforcingReconcileStatusAware is an interfce that must be implemented by a CRD type that has been enabled with ReconcileStatus, it can then benefit of a series of utility methods.
// +kubebuilder:object:generate:=false
type EnforcingReconcileStatusAware interface {
	GetEnforcingReconcileStatus() EnforcingReconcileStatus
	SetEnforcingReconcileStatus(enforcingReconcileStatus EnforcingReconcileStatus)
}


================================================
FILE: api/v1alpha1/groupversion_info.go
================================================
/*


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 contains API Schema definitions for the operator-utils v1alpha1 API group
// +kubebuilder:object:generate=true
// +groupName=operator-utils.example.io
package v1alpha1

import (
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
	// GroupVersion is group version used to register these objects
	GroupVersion = schema.GroupVersion{Group: "operator-utils.example.io", Version: "v1alpha1"}

	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

	// AddToScheme adds the types in this group-version to the given scheme.
	AddToScheme = SchemeBuilder.AddToScheme
)


================================================
FILE: api/v1alpha1/lockedpatch.go
================================================
package v1alpha1

import (
	"bytes"
	"context"
	"errors"
	"text/template"

	"github.com/redhat-cop/operator-utils/pkg/util/discoveryclient"
	"github.com/redhat-cop/operator-utils/pkg/util/dynamicclient"
	utiltemplates "github.com/redhat-cop/operator-utils/pkg/util/templates"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/rest"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"
)

// Patch describes a patch to be enforced at runtime
// +k8s:openapi-gen=true
type PatchSpec struct {
	//Name represents a unique name for this patch, it has no particular effect, except for internal bookeeping

	// SourceObjectRefs is an arrays of refereces to source objects that will be used as input for the template processing. These refernces must resolve to single instance. The resolution rule is as follows (+ present, - absent):
	// the King and APIVersion field are mandatory
	// +Namespace +Name: resolves to object <Namespace>/<Name>
	// +Namespace -Name: results in an error
	// -Namespace +Name: resolves to cluster-level object <Name>. If Kind is namespaced, this results in an error.
	// -Namespace -Name: results in an error
	// Name manespaces Namespace are evaluated as golang templates with the input of the template being the target object. When selecting multiple target, this allows for having specific source objects for each target.
	// ResourceVersion and UID are always ignored
	// If FieldPath is specified, the restuned object is calculated from the path, so for example if FieldPath=.spec, the only the spec portion of the object is returned.
	// The target object is always added as element zero of the array of the SourceObjectRefs
	// +kubebuilder:validation:Optional
	// +listType=atomic
	SourceObjectRefs []SourceObjectReference `json:"sourceObjectRefs,omitempty"`

	// TargetObjectRef is a reference to the object to which the pacth should be applied.
	// the King and APIVersion field are mandatory
	// the Name and Namespace field have the following meaning (+ present, - absent)
	// +Namespace +Name: apply the patch to the object: <Namespace>/<Name>
	// +Namespace -Name: apply the patch to all of the objects in <Namespace>
	// -Namespace +Name: apply the patch to the cluster-level object <Name>. If Kind is namespaced, this results in an error.
	// -Namespace -Name: if the kind is namespaced apply the patch to all of the objects in all of the namespaces. If the kind is not namespaced, apply the patch to all of the cluster level objects.
	// The lable selector can be used to further filter the selected objects.
	// +kubebuilder:validation:Required
	TargetObjectRef TargetObjectReference `json:"targetObjectRef,omitempty"`

	// PatchType is the type of patch to be applied, one of "application/json-patch+json"'"application/merge-patch+json","application/strategic-merge-patch+json","application/apply-patch+yaml"
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:Enum="application/json-patch+json";"application/merge-patch+json";"application/strategic-merge-patch+json";"application/apply-patch+yaml"
	// default:="application/strategic-merge-patch+json"
	PatchType types.PatchType `json:"patchType,omitempty"`

	// PatchTemplate is a go template that will be resolved using the SourceObjectRefs as parameters. The result must be a valid patch based on the pacth type and the target object.
	// +kubebuilder:validation:Required
	PatchTemplate string `json:"patchTemplate,omitempty"`
}

type TargetObjectReference struct {
	// API version of the referent.
	// +kubebuilder:validation:Required
	APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,5,opt,name=apiVersion"`

	// Kind of the referent.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
	// +kubebuilder:validation:Required
	Kind string `json:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"`

	// Namespace of the referent.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
	// +kubebuilder:validation:Optional
	Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,opt,name=namespace"`

	// Name of the referent.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
	// +kubebuilder:validation:Optional
	Name string `json:"name,omitempty" protobuf:"bytes,3,opt,name=name"`

	// LabelSelector selects objects by label
	// +kubebuilder:validation:Optional
	LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`

	// AnnotationSelector selects objects by label
	AnnotationSelector *metav1.LabelSelector `json:"annotationSelector,omitempty"`

	//apiResource caches apiResource for this targetReference
	apiResource *metav1.APIResource `json:"-"`
}

func (t *TargetObjectReference) getAPIReourceForGVK(context context.Context) (*metav1.APIResource, bool, error) {
	if t.apiResource != nil {
		return t.apiResource, true, nil
	}
	apiresource, found, err := discoveryclient.GetAPIResourceForGVK(context, schema.FromAPIVersionAndKind(t.APIVersion, t.Kind))
	if err != nil && found {
		t.apiResource = apiresource
	}
	return apiresource, found, err
}

func (t *TargetObjectReference) getDynamicClient(context context.Context) (dynamic.ResourceInterface, error) {
	log := log.FromContext(context)
	_, namespacedSelection, err := t.IsSelectingMultipleInstances(context)
	if err != nil {
		log.Error(err, "unable to determine if the target reference is selecting multiple instance", "targetReference", t)
		return nil, err
	}
	var ri dynamic.ResourceInterface
	nri, namespaced, err := dynamicclient.GetDynamicClientForGVK(context, schema.FromAPIVersionAndKind(t.APIVersion, t.Kind))
	if err != nil {
		log.Error(err, "unable to get dynamicClient on ", "gvk", schema.FromAPIVersionAndKind(t.APIVersion, t.Kind))
		return nil, err
	}
	if namespaced && namespacedSelection {
		ri = nri.Namespace(t.Namespace)
	} else {
		ri = nri
	}
	return ri, nil
}

func (t *TargetObjectReference) GetReferencedObjectWithName(context context.Context, namespacedName types.NamespacedName) (*unstructured.Unstructured, error) {
	log := log.FromContext(context)
	multiple, _, err := t.IsSelectingMultipleInstances(context)
	if err != nil {
		log.Error(err, "unable to determine if the target reference is selecting multiple instance", "targetReference", t)
		return nil, err
	}
	if !multiple {
		return t.GetReferencedObject(context)
	}
	targetCopy := t.DeepCopy()
	targetCopy.Name = namespacedName.Name
	namespaced, err := t.IsNamespaced(context)
	if err != nil {
		log.Error(err, "unable to determine if the target reference is namespaced", "targetReference", t)
		return nil, err
	}
	if namespaced {
		targetCopy.Namespace = namespacedName.Namespace
	}
	client, err := targetCopy.getDynamicClient(context)
	if err != nil {
		log.Error(err, "unable to get dynamic client with", "targetReference", targetCopy)
		return nil, err
	}
	obj, err := client.Get(context, targetCopy.Name, metav1.GetOptions{})
	if err != nil {
		log.Error(err, "unable to get referenced object", "targetReference", targetCopy)
		return nil, err
	}
	return obj, nil
}

func (t *TargetObjectReference) GetReferencedObject(context context.Context) (*unstructured.Unstructured, error) {
	log := log.FromContext(context)
	multiple, _, err := t.IsSelectingMultipleInstances(context)
	if err != nil {
		log.Error(err, "unable to determine if the target reference is selecting multiple instance", "targetReference", t)
		return nil, err
	}
	if multiple {
		return nil, errors.New("cannot call this method on a target that selects multiple instances")
	}
	dclient, err := t.getDynamicClient(context)
	if err != nil {
		log.Error(err, "unable to get dynamic client on", "targetReference", t)
		return nil, err
	}
	obj, err := dclient.Get(context, t.Name, metav1.GetOptions{})
	if err != nil {
		log.Error(err, "unable to get referenced ", "object", t)
		return nil, err
	}
	return obj, nil
}

func (t *TargetObjectReference) GetReferencedObjects(context context.Context) ([]unstructured.Unstructured, error) {
	log := log.FromContext(context)
	multiple, _, err := t.IsSelectingMultipleInstances(context)
	if err != nil {
		log.Error(err, "unable to determine if the target reference is selecting multiple instance", "targetReference", t)
		return nil, err
	}
	if !multiple {
		return nil, errors.New("cannot call this method on a target that does not select multiple instances")
	}
	dclient, err := t.getDynamicClient(context)
	if err != nil {
		log.Error(err, "unable to get dynamic client on", "targetReference", t)
		return nil, err
	}

	labelSelector, err := metav1.LabelSelectorAsSelector(t.LabelSelector)
	if err != nil {
		log.Error(err, "unable to process ", "labelSelector", t.LabelSelector)
		return nil, err
	}
	objList, err := dclient.List(context, metav1.ListOptions{
		LabelSelector: labelSelector.String(),
	})
	if err != nil {
		log.Error(err, "unable to list referenced ", "objects", t)
		return nil, err
	}
	var annotatonSelector labels.Selector
	if t.AnnotationSelector != nil {
		annotatonSelector, err = metav1.LabelSelectorAsSelector(t.AnnotationSelector)
		if err != nil {
			return nil, err
		}
	} else {
		annotatonSelector = labels.Everything()
	}
	//filter by annotation
	annotationFilteredList := []unstructured.Unstructured{}
	for i := range objList.Items {
		if annotatonSelector.Matches(labels.Set(objList.Items[i].GetAnnotations())) {
			annotationFilteredList = append(annotationFilteredList, objList.Items[i])
		}
	}
	//filter by name
	if t.Name != "" {
		filteredList := []unstructured.Unstructured{}
		for i := range annotationFilteredList {
			if t.Name == annotationFilteredList[i].GetName() {
				filteredList = append(filteredList, annotationFilteredList[i])
			}
		}
		return filteredList, nil
	}
	return objList.Items, nil
}

func (t *TargetObjectReference) IsNamespaced(context context.Context) (bool, error) {
	apiresource, found, err := t.getAPIReourceForGVK(context)
	if err != nil {
		return false, err
	}
	if !found {
		return false, errors.New("resource not found" + schema.FromAPIVersionAndKind(t.APIVersion, t.Kind).String())
	}
	return apiresource.Namespaced, nil
}

// IsSelectingMultipleInstances is a helper function to determine whether this targetObjectReference selects one or multiple instance.
func (t *TargetObjectReference) IsSelectingMultipleInstances(context context.Context) (multiple bool, namespacedSelection bool, err error) {
	log := log.FromContext(context)
	namespaced, err := t.IsNamespaced(context)
	if err != nil {
		log.Error(err, "Unable to determine if targetObjectReference is namespaced", "TargetObjectReference", t)
		return false, false, err
	}
	if namespaced {
		if t.Namespace == "" {
			return true, false, nil
		} else {
			if t.Name == "" {
				return true, true, nil
			} else {
				return false, true, nil
			}
		}
	} else {
		return t.Name == "", false, nil
	}
}

// Selects returns whether the passed object is selected by the current target reference
// requires context with log and restConfig
func (t *TargetObjectReference) Selects(context context.Context, obj client.Object) (bool, error) {
	log := log.FromContext(context)
	if apiversion, kind := obj.GetObjectKind().GroupVersionKind().ToAPIVersionAndKind(); t.Kind != kind || t.APIVersion != apiversion {
		return false, nil
	}
	var labelSelector labels.Selector
	var annotatonSelector labels.Selector
	var err error
	if t.LabelSelector != nil {
		labelSelector, err = metav1.LabelSelectorAsSelector(t.LabelSelector)
		if err != nil {
			return false, err
		}
	} else {
		labelSelector = labels.Everything()
	}
	if t.AnnotationSelector != nil {
		annotatonSelector, err = metav1.LabelSelectorAsSelector(t.AnnotationSelector)
		if err != nil {
			return false, err
		}
	} else {
		annotatonSelector = labels.Everything()
	}
	namespaced, err := discoveryclient.IsGVKNamespaced(context, obj.GetObjectKind().GroupVersionKind())
	if err != nil {
		log.Error(err, "Unable to determine if GVK is namespaced", "GVK", obj.GetObjectKind().GroupVersionKind())
		return false, err
	}
	if namespaced {
		if t.Namespace != "" {
			//we are selecting within a namespace
			if t.Namespace != obj.GetNamespace() {
				return false, nil
			}
		}
		if t.Name != "" {
			// we are matching on name
			return t.Name == obj.GetName(), nil
		} else {
			// we select via selectors
			return labelSelector.Matches(labels.Set(obj.GetLabels())) && annotatonSelector.Matches(labels.Set(obj.GetAnnotations())), nil
		}
	} else {
		//cluster object, we ignore namespace
		if t.Name != "" {
			// we select via name
			return t.Name == obj.GetName(), nil

		} else {
			// we select via selectors
			return labelSelector.Matches(labels.Set(obj.GetLabels())) && annotatonSelector.Matches(labels.Set(obj.GetAnnotations())), nil
		}
	}
}

// GetNameAndNamespace processes the templates for Name and Namespace of the sourceObjectReference
// requires context with log and restConfig
func (s *SourceObjectReference) GetNameAndNamespace(context context.Context, target *unstructured.Unstructured) (name string, namespace string, err error) {
	log := log.FromContext(context)
	name, err = processTemplate(context, s.Name, target.UnstructuredContent())
	if err != nil {
		log.Error(err, "unable to process template for", "name", s.Name)
		return "", "", err
	}
	namespace, err = processTemplate(context, s.Namespace, target.UnstructuredContent())
	if err != nil {
		log.Error(err, "unable to process template for", "namespace", s.Name)
		return "", "", err
	}
	return
}

func (t *SourceObjectReference) getAPIReourceForGVK(context context.Context) (*metav1.APIResource, bool, error) {
	if t.apiResource != nil {
		return t.apiResource, true, nil
	}
	apiresource, found, err := discoveryclient.GetAPIResourceForGVK(context, schema.FromAPIVersionAndKind(t.APIVersion, t.Kind))
	if err != nil && found {
		t.apiResource = apiresource
	}
	return apiresource, found, err
}

func (t *SourceObjectReference) getDynamicClient(context context.Context) (dynamic.ResourceInterface, error) {
	log := log.FromContext(context)

	var ri dynamic.ResourceInterface
	nri, namespaced, err := dynamicclient.GetDynamicClientForGVK(context, schema.FromAPIVersionAndKind(t.APIVersion, t.Kind))
	if err != nil {
		log.Error(err, "unable to get dynamicClient on ", "gvk", schema.FromAPIVersionAndKind(t.APIVersion, t.Kind))
		return nil, err
	}
	if namespaced {
		ri = nri.Namespace(t.Namespace)
	} else {
		ri = nri
	}
	return ri, nil
}

func (s *SourceObjectReference) GetReferencedObject(context context.Context, target *unstructured.Unstructured) (*unstructured.Unstructured, error) {
	log := log.FromContext(context)
	name, namespace, err := s.GetNameAndNamespace(context, target)
	if err != nil {
		log.Error(err, "unable to get name and namespaces on ", "SourceObjectReference", s, "with target", target)
		return nil, err
	}
	sourceCopy := s.DeepCopy()
	sourceCopy.Name = name
	sourceCopy.Namespace = namespace
	client, err := sourceCopy.getDynamicClient(context)
	if err != nil {
		log.Error(err, "unable to get dynamic client for ", "source", sourceCopy)
		return nil, err
	}
	obj, err := client.Get(context, name, metav1.GetOptions{})
	if err != nil {
		log.Error(err, "unable to get referenced object ", "sourceCopy", sourceCopy)
		return nil, err
	}
	return obj, nil
}

func processTemplate(context context.Context, templateString string, param interface{}) (string, error) {
	log := log.FromContext(context)
	restConfig := context.Value("restConfig").(*rest.Config)
	template, err := template.New(templateString).Funcs(utiltemplates.AdvancedTemplateFuncMap(restConfig, log)).Parse(templateString)
	if err != nil {
		log.Error(err, "unable to parse", "template", templateString)
		return "", err
	}
	var b bytes.Buffer
	err = template.Execute(&b, param)
	if err != nil {
		log.Error(err, "unable to process", "template", templateString, "with param", param)
		return "", err
	}
	return b.String(), nil
}

type SourceObjectReference struct {
	// API version of the referent.
	// +kubebuilder:validation:Required
	APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,5,opt,name=apiVersion"`

	// Kind of the referent.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
	// +kubebuilder:validation:Required
	Kind string `json:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"`

	// Namespace of the referent.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
	// +kubebuilder:validation:Optional
	Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,opt,name=namespace"`

	// Name of the referent.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
	// +kubebuilder:validation:Optional
	Name string `json:"name,omitempty" protobuf:"bytes,3,opt,name=name"`

	// If referring to a piece of an object instead of an entire object, this string
	// should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
	// For example, if the object reference is to a container within a pod, this would take on a value like:
	// "spec.containers{name}" (where "name" refers to the name of the container that triggered
	// the event) or if no container name is specified "spec.containers[2]" (container with
	// index 2 in this pod). This syntax is chosen only to have some well-defined way of
	// referencing a part of an object.
	// +kubebuilder:validation:Optional
	FieldPath string `json:"fieldPath,omitempty" protobuf:"bytes,7,opt,name=fieldPath"`

	//apiResource caches apiResource for this targetReference
	apiResource *metav1.APIResource `json:"-"`
}


================================================
FILE: api/v1alpha1/lockedresource.go
================================================
package v1alpha1

import (
	"k8s.io/apimachinery/pkg/runtime"
)

// LockedResource represents a resource to be enforced in a LockedResourceController and can be used in a API specification
// +k8s:openapi-gen=true
type LockedResource struct {

	// Object is a yaml representation of an API resource
	// +kubebuilder:validation:Required
	Object runtime.RawExtension `json:"object"`

	// ExludedPaths are a set of json paths that need not be considered by the LockedResourceReconciler
	// +kubebuilder:validation:Optional
	// +listType=set
	ExcludedPaths []string `json:"excludedPaths,omitempty"`
}

// LockedResourceTemplate represents a resource template in go language to be enforced in a LockedResourceController and can be used in a API specification
// +k8s:openapi-gen=true
type LockedResourceTemplate struct {

	// ObjectTemplate is a goland template. Whne processed, it must resolve to a yaml representation of an API resource
	// +kubebuilder:validation:Required
	ObjectTemplate string `json:"objectTemplate"`

	// ExludedPaths are a set of json paths that need not be considered by the LockedResourceReconciler
	// +kubebuilder:validation:Optional
	// +listType=set
	ExcludedPaths []string `json:"excludedPaths,omitempty"`
}


================================================
FILE: api/v1alpha1/mycrd_types.go
================================================
/*


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"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// MyCRDSpec defines the desired state of MyCRD
type MyCRDSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html
	Initialized bool `json:"initialized"`
	Valid       bool `json:"valid"`
	Error       bool `json:"error"`
}

// MyCRDStatus defines the observed state of MyCRD
type MyCRDStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html
	//     // +patchMergeKey=type
	//     // +patchStrategy=merge
	//     // +listType=map
	//     // +listMapKey=type
	//     Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`

	// +patchMergeKey=type
	// +patchStrategy=merge
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

func (m *MyCRD) GetConditions() []metav1.Condition {
	return m.Status.Conditions
}

func (m *MyCRD) SetConditions(conditions []metav1.Condition) {
	m.Status.Conditions = conditions
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// MyCRD is the Schema for the mycrds API
type MyCRD struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   MyCRDSpec   `json:"spec,omitempty"`
	Status MyCRDStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// MyCRDList contains a list of MyCRD
type MyCRDList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []MyCRD `json:"items"`
}

func init() {
	SchemeBuilder.Register(&MyCRD{}, &MyCRDList{})
}


================================================
FILE: api/v1alpha1/templatedenforcingcrd_types.go
================================================
/*


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"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// TemplatedEnforcingCRDSpec defines the desired state of TemplatedEnforcingCRD
type TemplatedEnforcingCRDSpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
	// +kubebuilder:validation:Optional
	// +listType=atomic
	Templates []LockedResourceTemplate `json:"templates,omitempty"`
}

// TemplatedEnforcingCRDStatus defines the observed state of TemplatedEnforcingCRD
type TemplatedEnforcingCRDStatus struct {
	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
	// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
	// Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
	// +kubebuilder:validation:Optional
	EnforcingReconcileStatus `json:",inline,omitempty"`
}

func (m *TemplatedEnforcingCRD) GetEnforcingReconcileStatus() EnforcingReconcileStatus {
	return m.Status.EnforcingReconcileStatus
}

func (m *TemplatedEnforcingCRD) SetEnforcingReconcileStatus(reconcileStatus EnforcingReconcileStatus) {
	m.Status.EnforcingReconcileStatus = reconcileStatus
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// TemplatedEnforcingCRD is the Schema for the templatedenforcingcrds API
type TemplatedEnforcingCRD struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   TemplatedEnforcingCRDSpec   `json:"spec,omitempty"`
	Status TemplatedEnforcingCRDStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// TemplatedEnforcingCRDList contains a list of TemplatedEnforcingCRD
type TemplatedEnforcingCRDList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []TemplatedEnforcingCRD `json:"items"`
}

func init() {
	SchemeBuilder.Register(&TemplatedEnforcingCRD{}, &TemplatedEnforcingCRDList{})
}


================================================
FILE: api/v1alpha1/zz_generated.deepcopy.go
================================================
//go:build !ignore_autogenerated
// +build !ignore_autogenerated

/*


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Code generated by controller-gen. DO NOT EDIT.

package v1alpha1

import (
	"k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ConditionMap) DeepCopyInto(out *ConditionMap) {
	{
		in := &in
		*out = make(ConditionMap, len(*in))
		for key, val := range *in {
			var outVal []v1.Condition
			if val == nil {
				(*out)[key] = nil
			} else {
				in, out := &val, &outVal
				*out = make(Conditions, len(*in))
				for i := range *in {
					(*in)[i].DeepCopyInto(&(*out)[i])
				}
			}
			(*out)[key] = outVal
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionMap.
func (in ConditionMap) DeepCopy() ConditionMap {
	if in == nil {
		return nil
	}
	out := new(ConditionMap)
	in.DeepCopyInto(out)
	return *out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Conditions) DeepCopyInto(out *Conditions) {
	{
		in := &in
		*out = make(Conditions, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions.
func (in Conditions) DeepCopy() Conditions {
	if in == nil {
		return nil
	}
	out := new(Conditions)
	in.DeepCopyInto(out)
	return *out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnforcingCRD) DeepCopyInto(out *EnforcingCRD) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
	in.Spec.DeepCopyInto(&out.Spec)
	in.Status.DeepCopyInto(&out.Status)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingCRD.
func (in *EnforcingCRD) DeepCopy() *EnforcingCRD {
	if in == nil {
		return nil
	}
	out := new(EnforcingCRD)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *EnforcingCRD) 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 *EnforcingCRDList) DeepCopyInto(out *EnforcingCRDList) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ListMeta.DeepCopyInto(&out.ListMeta)
	if in.Items != nil {
		in, out := &in.Items, &out.Items
		*out = make([]EnforcingCRD, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingCRDList.
func (in *EnforcingCRDList) DeepCopy() *EnforcingCRDList {
	if in == nil {
		return nil
	}
	out := new(EnforcingCRDList)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *EnforcingCRDList) 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 *EnforcingCRDSpec) DeepCopyInto(out *EnforcingCRDSpec) {
	*out = *in
	if in.Resources != nil {
		in, out := &in.Resources, &out.Resources
		*out = make([]LockedResource, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingCRDSpec.
func (in *EnforcingCRDSpec) DeepCopy() *EnforcingCRDSpec {
	if in == nil {
		return nil
	}
	out := new(EnforcingCRDSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnforcingCRDStatus) DeepCopyInto(out *EnforcingCRDStatus) {
	*out = *in
	in.EnforcingReconcileStatus.DeepCopyInto(&out.EnforcingReconcileStatus)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingCRDStatus.
func (in *EnforcingCRDStatus) DeepCopy() *EnforcingCRDStatus {
	if in == nil {
		return nil
	}
	out := new(EnforcingCRDStatus)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnforcingPatch) DeepCopyInto(out *EnforcingPatch) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
	in.Spec.DeepCopyInto(&out.Spec)
	in.Status.DeepCopyInto(&out.Status)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingPatch.
func (in *EnforcingPatch) DeepCopy() *EnforcingPatch {
	if in == nil {
		return nil
	}
	out := new(EnforcingPatch)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *EnforcingPatch) 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 *EnforcingPatchList) DeepCopyInto(out *EnforcingPatchList) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ListMeta.DeepCopyInto(&out.ListMeta)
	if in.Items != nil {
		in, out := &in.Items, &out.Items
		*out = make([]EnforcingPatch, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingPatchList.
func (in *EnforcingPatchList) DeepCopy() *EnforcingPatchList {
	if in == nil {
		return nil
	}
	out := new(EnforcingPatchList)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *EnforcingPatchList) 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 *EnforcingPatchSpec) DeepCopyInto(out *EnforcingPatchSpec) {
	*out = *in
	if in.Patches != nil {
		in, out := &in.Patches, &out.Patches
		*out = make(map[string]PatchSpec, len(*in))
		for key, val := range *in {
			(*out)[key] = *val.DeepCopy()
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingPatchSpec.
func (in *EnforcingPatchSpec) DeepCopy() *EnforcingPatchSpec {
	if in == nil {
		return nil
	}
	out := new(EnforcingPatchSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnforcingPatchStatus) DeepCopyInto(out *EnforcingPatchStatus) {
	*out = *in
	in.EnforcingReconcileStatus.DeepCopyInto(&out.EnforcingReconcileStatus)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingPatchStatus.
func (in *EnforcingPatchStatus) DeepCopy() *EnforcingPatchStatus {
	if in == nil {
		return nil
	}
	out := new(EnforcingPatchStatus)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnforcingReconcileStatus) DeepCopyInto(out *EnforcingReconcileStatus) {
	*out = *in
	if in.Conditions != nil {
		in, out := &in.Conditions, &out.Conditions
		*out = make([]v1.Condition, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
	if in.LockedResourceStatuses != nil {
		in, out := &in.LockedResourceStatuses, &out.LockedResourceStatuses
		*out = make(map[string]Conditions, len(*in))
		for key, val := range *in {
			var outVal []v1.Condition
			if val == nil {
				(*out)[key] = nil
			} else {
				in, out := &val, &outVal
				*out = make(Conditions, len(*in))
				for i := range *in {
					(*in)[i].DeepCopyInto(&(*out)[i])
				}
			}
			(*out)[key] = outVal
		}
	}
	if in.LockedPatchStatuses != nil {
		in, out := &in.LockedPatchStatuses, &out.LockedPatchStatuses
		*out = make(map[string]ConditionMap, len(*in))
		for key, val := range *in {
			var outVal map[string]Conditions
			if val == nil {
				(*out)[key] = nil
			} else {
				in, out := &val, &outVal
				*out = make(ConditionMap, len(*in))
				for key, val := range *in {
					var outVal []v1.Condition
					if val == nil {
						(*out)[key] = nil
					} else {
						in, out := &val, &outVal
						*out = make(Conditions, len(*in))
						for i := range *in {
							(*in)[i].DeepCopyInto(&(*out)[i])
						}
					}
					(*out)[key] = outVal
				}
			}
			(*out)[key] = outVal
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnforcingReconcileStatus.
func (in *EnforcingReconcileStatus) DeepCopy() *EnforcingReconcileStatus {
	if in == nil {
		return nil
	}
	out := new(EnforcingReconcileStatus)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LockedResource) DeepCopyInto(out *LockedResource) {
	*out = *in
	in.Object.DeepCopyInto(&out.Object)
	if in.ExcludedPaths != nil {
		in, out := &in.ExcludedPaths, &out.ExcludedPaths
		*out = make([]string, len(*in))
		copy(*out, *in)
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LockedResource.
func (in *LockedResource) DeepCopy() *LockedResource {
	if in == nil {
		return nil
	}
	out := new(LockedResource)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LockedResourceTemplate) DeepCopyInto(out *LockedResourceTemplate) {
	*out = *in
	if in.ExcludedPaths != nil {
		in, out := &in.ExcludedPaths, &out.ExcludedPaths
		*out = make([]string, len(*in))
		copy(*out, *in)
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LockedResourceTemplate.
func (in *LockedResourceTemplate) DeepCopy() *LockedResourceTemplate {
	if in == nil {
		return nil
	}
	out := new(LockedResourceTemplate)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MyCRD) DeepCopyInto(out *MyCRD) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
	out.Spec = in.Spec
	in.Status.DeepCopyInto(&out.Status)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MyCRD.
func (in *MyCRD) DeepCopy() *MyCRD {
	if in == nil {
		return nil
	}
	out := new(MyCRD)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MyCRD) 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 *MyCRDList) DeepCopyInto(out *MyCRDList) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ListMeta.DeepCopyInto(&out.ListMeta)
	if in.Items != nil {
		in, out := &in.Items, &out.Items
		*out = make([]MyCRD, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MyCRDList.
func (in *MyCRDList) DeepCopy() *MyCRDList {
	if in == nil {
		return nil
	}
	out := new(MyCRDList)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *MyCRDList) 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 *MyCRDSpec) DeepCopyInto(out *MyCRDSpec) {
	*out = *in
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MyCRDSpec.
func (in *MyCRDSpec) DeepCopy() *MyCRDSpec {
	if in == nil {
		return nil
	}
	out := new(MyCRDSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MyCRDStatus) DeepCopyInto(out *MyCRDStatus) {
	*out = *in
	if in.Conditions != nil {
		in, out := &in.Conditions, &out.Conditions
		*out = make([]v1.Condition, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MyCRDStatus.
func (in *MyCRDStatus) DeepCopy() *MyCRDStatus {
	if in == nil {
		return nil
	}
	out := new(MyCRDStatus)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PatchSpec) DeepCopyInto(out *PatchSpec) {
	*out = *in
	if in.SourceObjectRefs != nil {
		in, out := &in.SourceObjectRefs, &out.SourceObjectRefs
		*out = make([]SourceObjectReference, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
	in.TargetObjectRef.DeepCopyInto(&out.TargetObjectRef)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PatchSpec.
func (in *PatchSpec) DeepCopy() *PatchSpec {
	if in == nil {
		return nil
	}
	out := new(PatchSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SourceObjectReference) DeepCopyInto(out *SourceObjectReference) {
	*out = *in
	if in.apiResource != nil {
		in, out := &in.apiResource, &out.apiResource
		*out = new(v1.APIResource)
		(*in).DeepCopyInto(*out)
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceObjectReference.
func (in *SourceObjectReference) DeepCopy() *SourceObjectReference {
	if in == nil {
		return nil
	}
	out := new(SourceObjectReference)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetObjectReference) DeepCopyInto(out *TargetObjectReference) {
	*out = *in
	if in.LabelSelector != nil {
		in, out := &in.LabelSelector, &out.LabelSelector
		*out = new(v1.LabelSelector)
		(*in).DeepCopyInto(*out)
	}
	if in.AnnotationSelector != nil {
		in, out := &in.AnnotationSelector, &out.AnnotationSelector
		*out = new(v1.LabelSelector)
		(*in).DeepCopyInto(*out)
	}
	if in.apiResource != nil {
		in, out := &in.apiResource, &out.apiResource
		*out = new(v1.APIResource)
		(*in).DeepCopyInto(*out)
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetObjectReference.
func (in *TargetObjectReference) DeepCopy() *TargetObjectReference {
	if in == nil {
		return nil
	}
	out := new(TargetObjectReference)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TemplatedEnforcingCRD) DeepCopyInto(out *TemplatedEnforcingCRD) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
	in.Spec.DeepCopyInto(&out.Spec)
	in.Status.DeepCopyInto(&out.Status)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplatedEnforcingCRD.
func (in *TemplatedEnforcingCRD) DeepCopy() *TemplatedEnforcingCRD {
	if in == nil {
		return nil
	}
	out := new(TemplatedEnforcingCRD)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TemplatedEnforcingCRD) 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 *TemplatedEnforcingCRDList) DeepCopyInto(out *TemplatedEnforcingCRDList) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	in.ListMeta.DeepCopyInto(&out.ListMeta)
	if in.Items != nil {
		in, out := &in.Items, &out.Items
		*out = make([]TemplatedEnforcingCRD, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplatedEnforcingCRDList.
func (in *TemplatedEnforcingCRDList) DeepCopy() *TemplatedEnforcingCRDList {
	if in == nil {
		return nil
	}
	out := new(TemplatedEnforcingCRDList)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *TemplatedEnforcingCRDList) 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 *TemplatedEnforcingCRDSpec) DeepCopyInto(out *TemplatedEnforcingCRDSpec) {
	*out = *in
	if in.Templates != nil {
		in, out := &in.Templates, &out.Templates
		*out = make([]LockedResourceTemplate, len(*in))
		for i := range *in {
			(*in)[i].DeepCopyInto(&(*out)[i])
		}
	}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplatedEnforcingCRDSpec.
func (in *TemplatedEnforcingCRDSpec) DeepCopy() *TemplatedEnforcingCRDSpec {
	if in == nil {
		return nil
	}
	out := new(TemplatedEnforcingCRDSpec)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TemplatedEnforcingCRDStatus) DeepCopyInto(out *TemplatedEnforcingCRDStatus) {
	*out = *in
	in.EnforcingReconcileStatus.DeepCopyInto(&out.EnforcingReconcileStatus)
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplatedEnforcingCRDStatus.
func (in *TemplatedEnforcingCRDStatus) DeepCopy() *TemplatedEnforcingCRDStatus {
	if in == nil {
		return nil
	}
	out := new(TemplatedEnforcingCRDStatus)
	in.DeepCopyInto(out)
	return out
}


================================================
FILE: ci.Dockerfile
================================================
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /
COPY bin/manager .
USER 65532:65532

ENTRYPOINT ["/manager"]

================================================
FILE: config/certmanager/certificate.yaml
================================================
# The following manifests contain a self-signed issuer CR and a certificate CR.
# More document can be found at https://docs.cert-manager.io
# WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for 
# breaking changes
apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: selfsigned-issuer
  namespace: system
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: serving-cert  # this name should match the one appeared in kustomizeconfig.yaml
  namespace: system
spec:
  # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
  dnsNames:
  - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
  - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
  issuerRef:
    kind: Issuer
    name: selfsigned-issuer
  secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize


================================================
FILE: config/certmanager/kustomization.yaml
================================================
resources:
- certificate.yaml

configurations:
- kustomizeconfig.yaml


================================================
FILE: config/certmanager/kustomizeconfig.yaml
================================================
# This configuration is for teaching kustomize how to update name ref and var substitution 
nameReference:
- kind: Issuer
  group: cert-manager.io
  fieldSpecs:
  - kind: Certificate
    group: cert-manager.io
    path: spec/issuerRef/name

varReference:
- kind: Certificate
  group: cert-manager.io
  path: spec/commonName
- kind: Certificate
  group: cert-manager.io
  path: spec/dnsNames


================================================
FILE: config/crd/bases/operator-utils.example.io_enforcingcrds.yaml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.9.0
  creationTimestamp: null
  name: enforcingcrds.operator-utils.example.io
spec:
  group: operator-utils.example.io
  names:
    kind: EnforcingCRD
    listKind: EnforcingCRDList
    plural: enforcingcrds
    singular: enforcingcrd
  scope: Namespaced
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: EnforcingCRD is the Schema for the enforcingcrds API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: EnforcingCRDSpec defines the desired state of EnforcingCRD
            properties:
              resources:
                description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
                  Important: Run "operator-sdk generate k8s" to regenerate code after
                  modifying this file Add custom validation using kubebuilder tags:
                  https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html
                  Resources is a list of resource manifests that should be locked
                  into the specified configuration'
                items:
                  description: LockedResource represents a resource to be enforced
                    in a LockedResourceController and can be used in a API specification
                  properties:
                    excludedPaths:
                      description: ExludedPaths are a set of json paths that need
                        not be considered by the LockedResourceReconciler
                      items:
                        type: string
                      type: array
                      x-kubernetes-list-type: set
                    object:
                      description: Object is a yaml representation of an API resource
                      type: object
                  required:
                  - object
                  type: object
                type: array
                x-kubernetes-list-type: atomic
            type: object
          status:
            description: EnforcingCRDStatus defines the observed state of EnforcingCRD
            properties:
              conditions:
                description: ReconcileStatus this is the general status of the main
                  reconciler
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    \n type FooStatus struct{ // Represents the observations of a
                    foo's current state. // Known .status.conditions.type are: \"Available\",
                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating
                        details about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers
                        of specific condition types may define expected values and
                        meanings for this field, and whether the values are considered
                        a guaranteed API. The value should be a CamelCase string.
                        This field may not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
                x-kubernetes-list-map-keys:
                - type
                x-kubernetes-list-type: map
              lockedPatchStatuses:
                additionalProperties:
                  additionalProperties:
                    items:
                      description: "Condition contains details for one aspect of the
                        current state of this API Resource. --- This struct is intended
                        for direct use as an array at the field path .status.conditions.
                        \ For example, \n type FooStatus struct{ // Represents the
                        observations of a foo's current state. // Known .status.conditions.type
                        are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type
                        // +patchStrategy=merge // +listType=map // +listMapKey=type
                        Conditions []metav1.Condition `json:\"conditions,omitempty\"
                        patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                        \n // other fields }"
                      properties:
                        lastTransitionTime:
                          description: lastTransitionTime is the last time the condition
                            transitioned from one status to another. This should be
                            when the underlying condition changed.  If that is not
                            known, then using the time when the API field changed
                            is acceptable.
                          format: date-time
                          type: string
                        message:
                          description: message is a human readable message indicating
                            details about the transition. This may be an empty string.
                          maxLength: 32768
                          type: string
                        observedGeneration:
                          description: observedGeneration represents the .metadata.generation
                            that the condition was set based upon. For instance, if
                            .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
                            is 9, the condition is out of date with respect to the
                            current state of the instance.
                          format: int64
                          minimum: 0
                          type: integer
                        reason:
                          description: reason contains a programmatic identifier indicating
                            the reason for the condition's last transition. Producers
                            of specific condition types may define expected values
                            and meanings for this field, and whether the values are
                            considered a guaranteed API. The value should be a CamelCase
                            string. This field may not be empty.
                          maxLength: 1024
                          minLength: 1
                          pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                          type: string
                        status:
                          description: status of the condition, one of True, False,
                            Unknown.
                          enum:
                          - "True"
                          - "False"
                          - Unknown
                          type: string
                        type:
                          description: type of condition in CamelCase or in foo.example.com/CamelCase.
                            --- Many .condition.type values are consistent across
                            resources like Available, but because arbitrary conditions
                            can be useful (see .node.status.conditions), the ability
                            to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                          maxLength: 316
                          pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                          type: string
                      required:
                      - lastTransitionTime
                      - message
                      - reason
                      - status
                      - type
                      type: object
                    type: array
                  type: object
                description: LockedResourceStatuses contains the reconcile status
                  for each of the managed resources
                type: object
              lockedResourceStatuses:
                additionalProperties:
                  items:
                    description: "Condition contains details for one aspect of the
                      current state of this API Resource. --- This struct is intended
                      for direct use as an array at the field path .status.conditions.
                      \ For example, \n type FooStatus struct{ // Represents the observations
                      of a foo's current state. // Known .status.conditions.type are:
                      \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type
                      // +patchStrategy=merge // +listType=map // +listMapKey=type
                      Conditions []metav1.Condition `json:\"conditions,omitempty\"
                      patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                      \n // other fields }"
                    properties:
                      lastTransitionTime:
                        description: lastTransitionTime is the last time the condition
                          transitioned from one status to another. This should be
                          when the underlying condition changed.  If that is not known,
                          then using the time when the API field changed is acceptable.
                        format: date-time
                        type: string
                      message:
                        description: message is a human readable message indicating
                          details about the transition. This may be an empty string.
                        maxLength: 32768
                        type: string
                      observedGeneration:
                        description: observedGeneration represents the .metadata.generation
                          that the condition was set based upon. For instance, if
                          .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
                          is 9, the condition is out of date with respect to the current
                          state of the instance.
                        format: int64
                        minimum: 0
                        type: integer
                      reason:
                        description: reason contains a programmatic identifier indicating
                          the reason for the condition's last transition. Producers
                          of specific condition types may define expected values and
                          meanings for this field, and whether the values are considered
                          a guaranteed API. The value should be a CamelCase string.
                          This field may not be empty.
                        maxLength: 1024
                        minLength: 1
                        pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                        type: string
                      status:
                        description: status of the condition, one of True, False,
                          Unknown.
                        enum:
                        - "True"
                        - "False"
                        - Unknown
                        type: string
                      type:
                        description: type of condition in CamelCase or in foo.example.com/CamelCase.
                          --- Many .condition.type values are consistent across resources
                          like Available, but because arbitrary conditions can be
                          useful (see .node.status.conditions), the ability to deconflict
                          is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                        maxLength: 316
                        pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                        type: string
                    required:
                    - lastTransitionTime
                    - message
                    - reason
                    - status
                    - type
                    type: object
                  type: array
                description: LockedResourceStatuses contains the reconcile status
                  for each of the managed resources
                type: object
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}


================================================
FILE: config/crd/bases/operator-utils.example.io_enforcingpatches.yaml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.9.0
  creationTimestamp: null
  name: enforcingpatches.operator-utils.example.io
spec:
  group: operator-utils.example.io
  names:
    kind: EnforcingPatch
    listKind: EnforcingPatchList
    plural: enforcingpatches
    singular: enforcingpatch
  scope: Namespaced
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: EnforcingPatch is the Schema for the enforcingpatches API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: EnforcingPatchSpec defines the desired state of EnforcingPatch
            properties:
              patches:
                additionalProperties:
                  description: Patch describes a patch to be enforced at runtime
                  properties:
                    patchTemplate:
                      description: PatchTemplate is a go template that will be resolved
                        using the SourceObjectRefs as parameters. The result must
                        be a valid patch based on the pacth type and the target object.
                      type: string
                    patchType:
                      description: PatchType is the type of patch to be applied, one
                        of "application/json-patch+json"'"application/merge-patch+json","application/strategic-merge-patch+json","application/apply-patch+yaml"
                        default:="application/strategic-merge-patch+json"
                      enum:
                      - application/json-patch+json
                      - application/merge-patch+json
                      - application/strategic-merge-patch+json
                      - application/apply-patch+yaml
                      type: string
                    sourceObjectRefs:
                      description: 'SourceObjectRefs is an arrays of refereces to
                        source objects that will be used as input for the template
                        processing. These refernces must resolve to single instance.
                        The resolution rule is as follows (+ present, - absent): the
                        King and APIVersion field are mandatory -Namespace +Name:
                        resolves to cluster-level object <Name>. If Kind is namespaced,
                        this results in an error. -Namespace -Name: results in an
                        error Name manespaces Namespace are evaluated as golang templates
                        with the input of the template being the target object. When
                        selecting multiple target, this allows for having specific
                        source objects for each target. ResourceVersion and UID are
                        always ignored If FieldPath is specified, the restuned object
                        is calculated from the path, so for example if FieldPath=.spec,
                        the only the spec portion of the object is returned. The target
                        object is always added as element zero of the array of the
                        SourceObjectRefs'
                      items:
                        properties:
                          apiVersion:
                            description: API version of the referent.
                            type: string
                          fieldPath:
                            description: 'If referring to a piece of an object instead
                              of an entire object, this string should contain a valid
                              JSON/Go field access statement, such as desiredState.manifest.containers[2].
                              For example, if the object reference is to a container
                              within a pod, this would take on a value like: "spec.containers{name}"
                              (where "name" refers to the name of the container that
                              triggered the event) or if no container name is specified
                              "spec.containers[2]" (container with index 2 in this
                              pod). This syntax is chosen only to have some well-defined
                              way of referencing a part of an object.'
                            type: string
                          kind:
                            description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                            type: string
                          name:
                            description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                            type: string
                          namespace:
                            description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                            type: string
                        type: object
                      type: array
                      x-kubernetes-list-type: atomic
                    targetObjectRef:
                      description: 'TargetObjectRef is a reference to the object to
                        which the pacth should be applied. the King and APIVersion
                        field are mandatory the Name and Namespace field have the
                        following meaning (+ present, - absent) -Namespace +Name:
                        apply the patch to the cluster-level object <Name>. If Kind
                        is namespaced, this results in an error. -Namespace -Name:
                        if the kind is namespaced apply the patch to all of the objects
                        in all of the namespaces. If the kind is not namespaced, apply
                        the patch to all of the cluster level objects. The lable selector
                        can be used to further filter the selected objects.'
                      properties:
                        annotationSelector:
                          description: AnnotationSelector selects objects by label
                          properties:
                            matchExpressions:
                              description: matchExpressions is a list of label selector
                                requirements. The requirements are ANDed.
                              items:
                                description: A label selector requirement is a selector
                                  that contains values, a key, and an operator that
                                  relates the key and values.
                                properties:
                                  key:
                                    description: key is the label key that the selector
                                      applies to.
                                    type: string
                                  operator:
                                    description: operator represents a key's relationship
                                      to a set of values. Valid operators are In,
                                      NotIn, Exists and DoesNotExist.
                                    type: string
                                  values:
                                    description: values is an array of string values.
                                      If the operator is In or NotIn, the values array
                                      must be non-empty. If the operator is Exists
                                      or DoesNotExist, the values array must be empty.
                                      This array is replaced during a strategic merge
                                      patch.
                                    items:
                                      type: string
                                    type: array
                                required:
                                - key
                                - operator
                                type: object
                              type: array
                            matchLabels:
                              additionalProperties:
                                type: string
                              description: matchLabels is a map of {key,value} pairs.
                                A single {key,value} in the matchLabels map is equivalent
                                to an element of matchExpressions, whose key field
                                is "key", the operator is "In", and the values array
                                contains only "value". The requirements are ANDed.
                              type: object
                          type: object
                        apiVersion:
                          description: API version of the referent.
                          type: string
                        kind:
                          description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                          type: string
                        labelSelector:
                          description: LabelSelector selects objects by label
                          properties:
                            matchExpressions:
                              description: matchExpressions is a list of label selector
                                requirements. The requirements are ANDed.
                              items:
                                description: A label selector requirement is a selector
                                  that contains values, a key, and an operator that
                                  relates the key and values.
                                properties:
                                  key:
                                    description: key is the label key that the selector
                                      applies to.
                                    type: string
                                  operator:
                                    description: operator represents a key's relationship
                                      to a set of values. Valid operators are In,
                                      NotIn, Exists and DoesNotExist.
                                    type: string
                                  values:
                                    description: values is an array of string values.
                                      If the operator is In or NotIn, the values array
                                      must be non-empty. If the operator is Exists
                                      or DoesNotExist, the values array must be empty.
                                      This array is replaced during a strategic merge
                                      patch.
                                    items:
                                      type: string
                                    type: array
                                required:
                                - key
                                - operator
                                type: object
                              type: array
                            matchLabels:
                              additionalProperties:
                                type: string
                              description: matchLabels is a map of {key,value} pairs.
                                A single {key,value} in the matchLabels map is equivalent
                                to an element of matchExpressions, whose key field
                                is "key", the operator is "In", and the values array
                                contains only "value". The requirements are ANDed.
                              type: object
                          type: object
                        name:
                          description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                          type: string
                        namespace:
                          description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                          type: string
                      type: object
                  type: object
                description: Patches is a list of pacthes that should be encforced
                  at runtime.
                type: object
            type: object
          status:
            description: EnforcingPatchStatus defines the observed state of EnforcingPatch
            properties:
              conditions:
                description: ReconcileStatus this is the general status of the main
                  reconciler
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    \n type FooStatus struct{ // Represents the observations of a
                    foo's current state. // Known .status.conditions.type are: \"Available\",
                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating
                        details about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers
                        of specific condition types may define expected values and
                        meanings for this field, and whether the values are considered
                        a guaranteed API. The value should be a CamelCase string.
                        This field may not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
                x-kubernetes-list-map-keys:
                - type
                x-kubernetes-list-type: map
              lockedPatchStatuses:
                additionalProperties:
                  additionalProperties:
                    items:
                      description: "Condition contains details for one aspect of the
                        current state of this API Resource. --- This struct is intended
                        for direct use as an array at the field path .status.conditions.
                        \ For example, \n type FooStatus struct{ // Represents the
                        observations of a foo's current state. // Known .status.conditions.type
                        are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type
                        // +patchStrategy=merge // +listType=map // +listMapKey=type
                        Conditions []metav1.Condition `json:\"conditions,omitempty\"
                        patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                        \n // other fields }"
                      properties:
                        lastTransitionTime:
                          description: lastTransitionTime is the last time the condition
                            transitioned from one status to another. This should be
                            when the underlying condition changed.  If that is not
                            known, then using the time when the API field changed
                            is acceptable.
                          format: date-time
                          type: string
                        message:
                          description: message is a human readable message indicating
                            details about the transition. This may be an empty string.
                          maxLength: 32768
                          type: string
                        observedGeneration:
                          description: observedGeneration represents the .metadata.generation
                            that the condition was set based upon. For instance, if
                            .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
                            is 9, the condition is out of date with respect to the
                            current state of the instance.
                          format: int64
                          minimum: 0
                          type: integer
                        reason:
                          description: reason contains a programmatic identifier indicating
                            the reason for the condition's last transition. Producers
                            of specific condition types may define expected values
                            and meanings for this field, and whether the values are
                            considered a guaranteed API. The value should be a CamelCase
                            string. This field may not be empty.
                          maxLength: 1024
                          minLength: 1
                          pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                          type: string
                        status:
                          description: status of the condition, one of True, False,
                            Unknown.
                          enum:
                          - "True"
                          - "False"
                          - Unknown
                          type: string
                        type:
                          description: type of condition in CamelCase or in foo.example.com/CamelCase.
                            --- Many .condition.type values are consistent across
                            resources like Available, but because arbitrary conditions
                            can be useful (see .node.status.conditions), the ability
                            to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                          maxLength: 316
                          pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                          type: string
                      required:
                      - lastTransitionTime
                      - message
                      - reason
                      - status
                      - type
                      type: object
                    type: array
                  type: object
                description: LockedResourceStatuses contains the reconcile status
                  for each of the managed resources
                type: object
              lockedResourceStatuses:
                additionalProperties:
                  items:
                    description: "Condition contains details for one aspect of the
                      current state of this API Resource. --- This struct is intended
                      for direct use as an array at the field path .status.conditions.
                      \ For example, \n type FooStatus struct{ // Represents the observations
                      of a foo's current state. // Known .status.conditions.type are:
                      \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type
                      // +patchStrategy=merge // +listType=map // +listMapKey=type
                      Conditions []metav1.Condition `json:\"conditions,omitempty\"
                      patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                      \n // other fields }"
                    properties:
                      lastTransitionTime:
                        description: lastTransitionTime is the last time the condition
                          transitioned from one status to another. This should be
                          when the underlying condition changed.  If that is not known,
                          then using the time when the API field changed is acceptable.
                        format: date-time
                        type: string
                      message:
                        description: message is a human readable message indicating
                          details about the transition. This may be an empty string.
                        maxLength: 32768
                        type: string
                      observedGeneration:
                        description: observedGeneration represents the .metadata.generation
                          that the condition was set based upon. For instance, if
                          .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
                          is 9, the condition is out of date with respect to the current
                          state of the instance.
                        format: int64
                        minimum: 0
                        type: integer
                      reason:
                        description: reason contains a programmatic identifier indicating
                          the reason for the condition's last transition. Producers
                          of specific condition types may define expected values and
                          meanings for this field, and whether the values are considered
                          a guaranteed API. The value should be a CamelCase string.
                          This field may not be empty.
                        maxLength: 1024
                        minLength: 1
                        pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                        type: string
                      status:
                        description: status of the condition, one of True, False,
                          Unknown.
                        enum:
                        - "True"
                        - "False"
                        - Unknown
                        type: string
                      type:
                        description: type of condition in CamelCase or in foo.example.com/CamelCase.
                          --- Many .condition.type values are consistent across resources
                          like Available, but because arbitrary conditions can be
                          useful (see .node.status.conditions), the ability to deconflict
                          is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                        maxLength: 316
                        pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                        type: string
                    required:
                    - lastTransitionTime
                    - message
                    - reason
                    - status
                    - type
                    type: object
                  type: array
                description: LockedResourceStatuses contains the reconcile status
                  for each of the managed resources
                type: object
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}


================================================
FILE: config/crd/bases/operator-utils.example.io_mycrds.yaml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.9.0
  creationTimestamp: null
  name: mycrds.operator-utils.example.io
spec:
  group: operator-utils.example.io
  names:
    kind: MyCRD
    listKind: MyCRDList
    plural: mycrds
    singular: mycrd
  scope: Namespaced
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: MyCRD is the Schema for the mycrds API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: MyCRDSpec defines the desired state of MyCRD
            properties:
              error:
                type: boolean
              initialized:
                description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
                  Important: Run "operator-sdk generate k8s" to regenerate code after
                  modifying this file Add custom validation using kubebuilder tags:
                  https://book.kubebuilder.io/beyond_basics/generating_crd.html'
                type: boolean
              valid:
                type: boolean
            required:
            - error
            - initialized
            - valid
            type: object
          status:
            description: MyCRDStatus defines the observed state of MyCRD
            properties:
              conditions:
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    \n type FooStatus struct{ // Represents the observations of a
                    foo's current state. // Known .status.conditions.type are: \"Available\",
                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating
                        details about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers
                        of specific condition types may define expected values and
                        meanings for this field, and whether the values are considered
                        a guaranteed API. The value should be a CamelCase string.
                        This field may not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
                x-kubernetes-list-map-keys:
                - type
                x-kubernetes-list-type: map
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}


================================================
FILE: config/crd/bases/operator-utils.example.io_templatedenforcingcrds.yaml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.9.0
  creationTimestamp: null
  name: templatedenforcingcrds.operator-utils.example.io
spec:
  group: operator-utils.example.io
  names:
    kind: TemplatedEnforcingCRD
    listKind: TemplatedEnforcingCRDList
    plural: templatedenforcingcrds
    singular: templatedenforcingcrd
  scope: Namespaced
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: TemplatedEnforcingCRD is the Schema for the templatedenforcingcrds
          API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: TemplatedEnforcingCRDSpec defines the desired state of TemplatedEnforcingCRD
            properties:
              templates:
                description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
                  Important: Run "operator-sdk generate k8s" to regenerate code after
                  modifying this file Add custom validation using kubebuilder tags:
                  https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
                items:
                  description: LockedResourceTemplate represents a resource template
                    in go language to be enforced in a LockedResourceController and
                    can be used in a API specification
                  properties:
                    excludedPaths:
                      description: ExludedPaths are a set of json paths that need
                        not be considered by the LockedResourceReconciler
                      items:
                        type: string
                      type: array
                      x-kubernetes-list-type: set
                    objectTemplate:
                      description: ObjectTemplate is a goland template. Whne processed,
                        it must resolve to a yaml representation of an API resource
                      type: string
                  required:
                  - objectTemplate
                  type: object
                type: array
                x-kubernetes-list-type: atomic
            type: object
          status:
            description: TemplatedEnforcingCRDStatus defines the observed state of
              TemplatedEnforcingCRD
            properties:
              conditions:
                description: ReconcileStatus this is the general status of the main
                  reconciler
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    \n type FooStatus struct{ // Represents the observations of a
                    foo's current state. // Known .status.conditions.type are: \"Available\",
                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating
                        details about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers
                        of specific condition types may define expected values and
                        meanings for this field, and whether the values are considered
                        a guaranteed API. The value should be a CamelCase string.
                        This field may not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
                x-kubernetes-list-map-keys:
                - type
                x-kubernetes-list-type: map
              lockedPatchStatuses:
                additionalProperties:
                  additionalProperties:
                    items:
                      description: "Condition contains details for one aspect of the
                        current state of this API Resource. --- This struct is intended
                        for direct use as an array at the field path .status.conditions.
                        \ For example, \n type FooStatus struct{ // Represents the
                        observations of a foo's current state. // Known .status.conditions.type
                        are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type
                        // +patchStrategy=merge // +listType=map // +listMapKey=type
                        Conditions []metav1.Condition `json:\"conditions,omitempty\"
                        patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                        \n // other fields }"
                      properties:
                        lastTransitionTime:
                          description: lastTransitionTime is the last time the condition
                            transitioned from one status to another. This should be
                            when the underlying condition changed.  If that is not
                            known, then using the time when the API field changed
                            is acceptable.
                          format: date-time
                          type: string
                        message:
                          description: message is a human readable message indicating
                            details about the transition. This may be an empty string.
                          maxLength: 32768
                          type: string
                        observedGeneration:
                          description: observedGeneration represents the .metadata.generation
                            that the condition was set based upon. For instance, if
                            .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
                            is 9, the condition is out of date with respect to the
                            current state of the instance.
                          format: int64
                          minimum: 0
                          type: integer
                        reason:
                          description: reason contains a programmatic identifier indicating
                            the reason for the condition's last transition. Producers
                            of specific condition types may define expected values
                            and meanings for this field, and whether the values are
                            considered a guaranteed API. The value should be a CamelCase
                            string. This field may not be empty.
                          maxLength: 1024
                          minLength: 1
                          pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                          type: string
                        status:
                          description: status of the condition, one of True, False,
                            Unknown.
                          enum:
                          - "True"
                          - "False"
                          - Unknown
                          type: string
                        type:
                          description: type of condition in CamelCase or in foo.example.com/CamelCase.
                            --- Many .condition.type values are consistent across
                            resources like Available, but because arbitrary conditions
                            can be useful (see .node.status.conditions), the ability
                            to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                          maxLength: 316
                          pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                          type: string
                      required:
                      - lastTransitionTime
                      - message
                      - reason
                      - status
                      - type
                      type: object
                    type: array
                  type: object
                description: LockedResourceStatuses contains the reconcile status
                  for each of the managed resources
                type: object
              lockedResourceStatuses:
                additionalProperties:
                  items:
                    description: "Condition contains details for one aspect of the
                      current state of this API Resource. --- This struct is intended
                      for direct use as an array at the field path .status.conditions.
                      \ For example, \n type FooStatus struct{ // Represents the observations
                      of a foo's current state. // Known .status.conditions.type are:
                      \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type
                      // +patchStrategy=merge // +listType=map // +listMapKey=type
                      Conditions []metav1.Condition `json:\"conditions,omitempty\"
                      patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                      \n // other fields }"
                    properties:
                      lastTransitionTime:
                        description: lastTransitionTime is the last time the condition
                          transitioned from one status to another. This should be
                          when the underlying condition changed.  If that is not known,
                          then using the time when the API field changed is acceptable.
                        format: date-time
                        type: string
                      message:
                        description: message is a human readable message indicating
                          details about the transition. This may be an empty string.
                        maxLength: 32768
                        type: string
                      observedGeneration:
                        description: observedGeneration represents the .metadata.generation
                          that the condition was set based upon. For instance, if
                          .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
                          is 9, the condition is out of date with respect to the current
                          state of the instance.
                        format: int64
                        minimum: 0
                        type: integer
                      reason:
                        description: reason contains a programmatic identifier indicating
                          the reason for the condition's last transition. Producers
                          of specific condition types may define expected values and
                          meanings for this field, and whether the values are considered
                          a guaranteed API. The value should be a CamelCase string.
                          This field may not be empty.
                        maxLength: 1024
                        minLength: 1
                        pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                        type: string
                      status:
                        description: status of the condition, one of True, False,
                          Unknown.
                        enum:
                        - "True"
                        - "False"
                        - Unknown
                        type: string
                      type:
                        description: type of condition in CamelCase or in foo.example.com/CamelCase.
                          --- Many .condition.type values are consistent across resources
                          like Available, but because arbitrary conditions can be
                          useful (see .node.status.conditions), the ability to deconflict
                          is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                        maxLength: 316
                        pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                        type: string
                    required:
                    - lastTransitionTime
                    - message
                    - reason
                    - status
                    - type
                    type: object
                  type: array
                description: LockedResourceStatuses contains the reconcile status
                  for each of the managed resources
                type: object
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}


================================================
FILE: config/crd/kustomization.yaml
================================================
# This kustomization.yaml is not intended to be run by itself,
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
- bases/operator-utils.example.io_mycrds.yaml
- bases/operator-utils.example.io_enforcingcrds.yaml
- bases/operator-utils.example.io_enforcingpatches.yaml
- bases/operator-utils.example.io_templatedenforcingcrds.yaml
# +kubebuilder:scaffold:crdkustomizeresource

patchesStrategicMerge:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_mycrds.yaml
#- patches/webhook_in_enforcingcrds.yaml
#- patches/webhook_in_enforcingpatches.yaml
#- patches/webhook_in_templatedenforcingcrds.yaml
# +kubebuilder:scaffold:crdkustomizewebhookpatch

# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
# patches here are for enabling the CA injection for each CRD
#- patches/cainjection_in_mycrds.yaml
#- patches/cainjection_in_enforcingcrds.yaml
#- patches/cainjection_in_enforcingpatches.yaml
#- patches/cainjection_in_templatedenforcingcrds.yaml
# +kubebuilder:scaffold:crdkustomizecainjectionpatch

# the following config is for teaching kustomize how to do kustomization for CRDs.
configurations:
- kustomizeconfig.yaml


================================================
FILE: config/crd/kustomizeconfig.yaml
================================================
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
nameReference:
- kind: Service
  version: v1
  fieldSpecs:
  - kind: CustomResourceDefinition
    group: apiextensions.k8s.io
    path: spec/conversion/webhookClientConfig/service/name

namespace:
- kind: CustomResourceDefinition
  group: apiextensions.k8s.io
  path: spec/conversion/webhookClientConfig/service/namespace
  create: false

varReference:
- path: metadata/annotations


================================================
FILE: config/crd/patches/cainjection_in_enforcingcrds.yaml
================================================
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
  name: enforcingcrds.operator-utils.example.io


================================================
FILE: config/crd/patches/cainjection_in_enforcingpatches.yaml
================================================
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
  name: enforcingpatches.operator-utils.example.io


================================================
FILE: config/crd/patches/cainjection_in_mycrds.yaml
================================================
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
  name: mycrds.operator-utils.example.io


================================================
FILE: config/crd/patches/cainjection_in_templatedenforcingcrds.yaml
================================================
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
  name: templatedenforcingcrds.operator-utils.example.io


================================================
FILE: config/crd/patches/webhook_in_enforcingcrds.yaml
================================================
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: enforcingcrds.operator-utils.example.io
spec:
  conversion:
    strategy: Webhook
    webhookClientConfig:
      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
      caBundle: Cg==
      service:
        namespace: system
        name: webhook-service
        path: /convert


================================================
FILE: config/crd/patches/webhook_in_enforcingpatches.yaml
================================================
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: enforcingpatches.operator-utils.example.io
spec:
  conversion:
    strategy: Webhook
    webhookClientConfig:
      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
      caBundle: Cg==
      service:
        namespace: system
        name: webhook-service
        path: /convert


================================================
FILE: config/crd/patches/webhook_in_mycrds.yaml
================================================
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: mycrds.operator-utils.example.io
spec:
  conversion:
    strategy: Webhook
    webhookClientConfig:
      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
      caBundle: Cg==
      service:
        namespace: system
        name: webhook-service
        path: /convert


================================================
FILE: config/crd/patches/webhook_in_templatedenforcingcrds.yaml
================================================
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: templatedenforcingcrds.operator-utils.example.io
spec:
  conversion:
    strategy: Webhook
    webhookClientConfig:
      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
      caBundle: Cg==
      service:
        namespace: system
        name: webhook-service
        path: /convert


================================================
FILE: config/default/kustomization.yaml
================================================
# Adds namespace to all resources.
namespace: operator-utils

# Value of this field is prepended to the
# names of all resources, e.g. a deployment named
# "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace
# field above.
namePrefix: operator-utils-

# Labels to add to all resources and selectors.
#commonLabels:
#  someName: someValue

bases:
- ../crd
- ../rbac
- ../manager
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
#- ../certmanager
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
- ../prometheus

patchesStrategicMerge:
  # Protect the /metrics endpoint by putting it behind auth.
  # If you want your controller-manager to expose the /metrics
  # endpoint w/o any authn/z, please comment the following line.
- manager_auth_proxy_patch.yaml

# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- manager_webhook_patch.yaml

# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
# 'CERTMANAGER' needs to be enabled to use ca injection
#- webhookcainjection_patch.yaml

# the following config is for teaching kustomize how to do var substitution
vars:

- name: METRICS_SERVICE_NAME
  objref:
    kind: Service
    version: v1
    name: controller-manager-metrics
- name: METRICS_SERVICE_NAMESPACE
  objref:
    kind: Service
    version: v1
    name: controller-manager-metrics
  fieldref:
    fieldpath: metadata.namespace

# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
#  objref:
#    kind: Certificate
#    group: cert-manager.io
#    version: v1alpha2
#    name: serving-cert # this name should match the one in certificate.yaml
#  fieldref:
#    fieldpath: metadata.namespace
#- name: CERTIFICATE_NAME
#  objref:
#    kind: Certificate
#    group: cert-manager.io
#    version: v1alpha2
#    name: serving-cert # this name should match the one in certificate.yaml
#- name: SERVICE_NAMESPACE # namespace of the service
#  objref:
#    kind: Service
#    version: v1
#    name: webhook-service
#  fieldref:
#    fieldpath: metadata.namespace
#- name: SERVICE_NAME
#  objref:
#    kind: Service
#    version: v1
#    name: webhook-service


================================================
FILE: config/default/manager_auth_proxy_patch.yaml
================================================
# This patch inject a sidecar container which is a HTTP proxy for the 
# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: controller-manager
  namespace: system
spec:
  template:
    spec:
      containers:
      - name: kube-rbac-proxy
        image: quay.io/coreos/kube-rbac-proxy:v0.11.0
        args:
        - "--secure-listen-address=0.0.0.0:8443"
        - "--upstream=http://127.0.0.1:8080/"
        - "--logtostderr=true"
        - "--v=0"
        - "--tls-cert-file=/etc/certs/tls/tls.crt"
        - "--tls-private-key-file=/etc/certs/tls/tls.key"
        volumeMounts:
          - mountPath: /etc/certs/tls
            name: tls-cert         
        ports:
        - containerPort: 8443
          name: https
        resources:
          limits:
            cpu: 500m
            memory: 128Mi
          requests:
            cpu: 5m
            memory: 64Mi
      - name: manager
        args:
        - "--metrics-addr=127.0.0.1:8080"
        - "--enable-leader-election"
      volumes:
      - name: tls-cert
        secret:
          defaultMode: 420
          secretName: operator-utils-operator-certs          


================================================
FILE: config/default/manager_webhook_patch.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
  name: controller-manager
  namespace: system
spec:
  template:
    spec:
      containers:
      - name: manager
        ports:
        - containerPort: 9443
          name: webhook-server
          protocol: TCP
        volumeMounts:
        - mountPath: /tmp/k8s-webhook-server/serving-certs
          name: cert
          readOnly: true
      volumes:
      - name: cert
        secret:
          defaultMode: 420
          secretName: webhook-server-cert


================================================
FILE: config/default/webhookcainjection_patch.yaml
================================================
# This patch add annotation to admission webhook config and
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
  name: mutating-webhook-configuration
  annotations:
    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: validating-webhook-configuration
  annotations:
    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)


================================================
FILE: config/helmchart/.helmignore
================================================
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/


================================================
FILE: config/helmchart/Chart.yaml.tpl
================================================
apiVersion: v1
name: operator-utils
version: ${version}
appVersion: ${version}
description: Helm chart that deploys operator-utils
keywords:
  - volume
  - storage
  - csi
  - expansion
  - monitoring
sources:
  - https://github.com/redhat-cop/operator-utils
engine: gotpl

================================================
FILE: config/helmchart/kustomization.yaml
================================================
# Adds namespace to all resources.
namespace: release-namespace

# Value of this field is prepended to the
# names of all resources, e.g. a deployment named
# "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace
# field above.
namePrefix: operator-utils-

# Labels to add to all resources and selectors.
#commonLabels:
#  someName: someValue

bases:
- ../rbac
- ../prometheus

vars:
- name: METRICS_SERVICE_NAME
  objref:
    kind: Service
    version: v1
    name: controller-manager-metrics
- name: METRICS_SERVICE_NAMESPACE
  objref:
    kind: Service
    version: v1
    name: controller-manager-metrics
  fieldref:
    fieldpath: metadata.namespace


================================================
FILE: config/helmchart/templates/_helpers.tpl
================================================
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "operator-utils.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "operator-utils.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "operator-utils.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "operator-utils.labels" -}}
helm.sh/chart: {{ include "operator-utils.chart" . }}
{{ include "operator-utils.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "operator-utils.selectorLabels" -}}
app.kubernetes.io/name: {{ include "operator-utils.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "operator-utils.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "operator-utils.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}


================================================
FILE: config/helmchart/templates/manager.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "operator-utils.fullname" . }}
  labels:
    {{- include "operator-utils.labels" . | nindent 4 }}
    operator: operator-utils-operator
spec:
  selector:
    matchLabels:
      {{- include "operator-utils.selectorLabels" . | nindent 6 }}
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
    {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
    {{- end }}
      labels:
        {{- include "operator-utils.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: operator-utils-controller-manager    
      containers:
      - args:
        - --secure-listen-address=0.0.0.0:8443
        - --upstream=http://127.0.0.1:8080/
        - --logtostderr=true
        - --tls-cert-file=/etc/certs/tls/tls.crt
        - --tls-private-key-file=/etc/certs/tls/tls.key
        - --v=10
        image: "{{ .Values.kube_rbac_proxy.image.repository }}:{{ .Values.kube_rbac_proxy.image.tag }}"
        name: kube-rbac-proxy
        ports:
        - containerPort: 8443
          name: https
        volumeMounts:
        - mountPath: /etc/certs/tls
          name: tls-cert
        imagePullPolicy: {{ .Values.kube_rbac_proxy.image.pullPolicy }}
        resources:
          {{- toYaml .Values.kube_rbac_proxy.resources | nindent 10 }}      
      - command:
        - /manager
        args:
        - --enable-leader-election
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        name: {{ .C
Download .txt
gitextract_fz5mf0kc/

├── .github/
│   └── workflows/
│       ├── pr.yaml
│       └── push.yaml
├── .gitignore
├── Dockerfile
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── api/
│   └── v1alpha1/
│       ├── enforcingcrd_types.go
│       ├── enforcingpatch_types.go
│       ├── enforcingreconcilerstatus.go
│       ├── groupversion_info.go
│       ├── lockedpatch.go
│       ├── lockedresource.go
│       ├── mycrd_types.go
│       ├── templatedenforcingcrd_types.go
│       └── zz_generated.deepcopy.go
├── ci.Dockerfile
├── config/
│   ├── certmanager/
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── crd/
│   │   ├── bases/
│   │   │   ├── operator-utils.example.io_enforcingcrds.yaml
│   │   │   ├── operator-utils.example.io_enforcingpatches.yaml
│   │   │   ├── operator-utils.example.io_mycrds.yaml
│   │   │   └── operator-utils.example.io_templatedenforcingcrds.yaml
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches/
│   │       ├── cainjection_in_enforcingcrds.yaml
│   │       ├── cainjection_in_enforcingpatches.yaml
│   │       ├── cainjection_in_mycrds.yaml
│   │       ├── cainjection_in_templatedenforcingcrds.yaml
│   │       ├── webhook_in_enforcingcrds.yaml
│   │       ├── webhook_in_enforcingpatches.yaml
│   │       ├── webhook_in_mycrds.yaml
│   │       └── webhook_in_templatedenforcingcrds.yaml
│   ├── default/
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── helmchart/
│   │   ├── .helmignore
│   │   ├── Chart.yaml.tpl
│   │   ├── kustomization.yaml
│   │   ├── templates/
│   │   │   ├── _helpers.tpl
│   │   │   └── manager.yaml
│   │   └── values.yaml.tpl
│   ├── local-development/
│   │   └── kustomization.yaml
│   ├── manager/
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── manifests/
│   │   ├── bases/
│   │   │   └── operator-utils.clusterserviceversion.yaml
│   │   └── kustomization.yaml
│   ├── prometheus/
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── monitor.yaml
│   ├── rbac/
│   │   ├── auth_proxy_client_clusterrole.yaml
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── enforcingcrd_editor_role.yaml
│   │   ├── enforcingcrd_viewer_role.yaml
│   │   ├── enforcingpatch_editor_role.yaml
│   │   ├── enforcingpatch_viewer_role.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   ├── mycrd_editor_role.yaml
│   │   ├── mycrd_viewer_role.yaml
│   │   ├── role.yaml
│   │   ├── role_binding.yaml
│   │   ├── templatedenforcingcrd_editor_role.yaml
│   │   └── templatedenforcingcrd_viewer_role.yaml
│   ├── samples/
│   │   ├── kustomization.yaml
│   │   ├── operator-utils_v1alpha1_enforcingcrd.yaml
│   │   ├── operator-utils_v1alpha1_enforcingpatch.yaml
│   │   ├── operator-utils_v1alpha1_mycrd.yaml
│   │   └── operator-utils_v1alpha1_templatedenforcingcrd.yaml
│   ├── scorecard/
│   │   ├── bases/
│   │   │   └── config.yaml
│   │   ├── kustomization.yaml
│   │   └── patches/
│   │       ├── basic.config.yaml
│   │       └── olm.config.yaml
│   └── webhook/
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── controllers/
│   ├── enforcingcrd_controller.go
│   ├── enforcingpatch_controller.go
│   ├── mycrd_controller.go
│   ├── suite_test.go
│   └── templatedenforcingcrd_controller.go
├── go.mod
├── go.sum
├── hack/
│   └── boilerplate.go.txt
├── main.go
├── pkg/
│   └── util/
│       ├── apis/
│       │   ├── conditions.go
│       │   └── key.go
│       ├── crud/
│       │   └── crudutils.go
│       ├── discoveryclient/
│       │   └── discoveryclientutils.go
│       ├── dynamicclient/
│       │   └── dynamicclientutils.go
│       ├── finalizer.go
│       ├── lockedresourcecontroller/
│       │   ├── enforcing-reconciler.go
│       │   ├── locked-resource-manager.go
│       │   ├── lockedpatch/
│       │   │   └── lockedpatch.go
│       │   ├── lockedresource/
│       │   │   ├── lockedresource.go
│       │   │   ├── lockedresourceset/
│       │   │   │   ├── lockedresourceset.go
│       │   │   │   ├── lockedresourceset_bench_test.go
│       │   │   │   └── lockedresourceset_test.go
│       │   │   └── patch.go
│       │   ├── patch-reconciler.go
│       │   └── resource-reconciler.go
│       ├── owner.go
│       ├── predicates.go
│       ├── reconciler.go
│       ├── stoppablemanager/
│       │   └── stoppable-manager.go
│       └── templates/
│           ├── advanced-funcmap.go
│           └── templates.go
├── test/
│   ├── enforcing-patch-multiple-cluster-level.yaml
│   ├── enforcing-patch-multiple.yaml
│   ├── enforcing-patch.yaml
│   ├── enforcing_cr.yaml
│   ├── failing-enforcing_cr.yaml
│   ├── mycrd_cr.yaml
│   └── templatedenforcing_cr.yaml
└── testbin/
    └── setup-envtest.sh
Download .txt
SYMBOL INDEX (342 symbols across 34 files)

FILE: api/v1alpha1/enforcingcrd_types.go
  type EnforcingCRDSpec (line 27) | type EnforcingCRDSpec struct
  type EnforcingCRDStatus (line 38) | type EnforcingCRDStatus struct
  type EnforcingCRD (line 58) | type EnforcingCRD struct
    method GetEnforcingReconcileStatus (line 46) | func (m *EnforcingCRD) GetEnforcingReconcileStatus() EnforcingReconcil...
    method SetEnforcingReconcileStatus (line 50) | func (m *EnforcingCRD) SetEnforcingReconcileStatus(reconcileStatus Enf...
  type EnforcingCRDList (line 69) | type EnforcingCRDList struct
  function init (line 75) | func init() {

FILE: api/v1alpha1/enforcingpatch_types.go
  type EnforcingPatchSpec (line 27) | type EnforcingPatchSpec struct
  type EnforcingPatchStatus (line 38) | type EnforcingPatchStatus struct
  type EnforcingPatch (line 57) | type EnforcingPatch struct
    method GetEnforcingReconcileStatus (line 45) | func (m *EnforcingPatch) GetEnforcingReconcileStatus() EnforcingReconc...
    method SetEnforcingReconcileStatus (line 49) | func (m *EnforcingPatch) SetEnforcingReconcileStatus(reconcileStatus E...
  type EnforcingPatchList (line 68) | type EnforcingPatchList struct
  function init (line 74) | func init() {

FILE: api/v1alpha1/enforcingreconcilerstatus.go
  type Conditions (line 7) | type Conditions
  type ConditionMap (line 10) | type ConditionMap
  type EnforcingReconcileStatus (line 13) | type EnforcingReconcileStatus struct
  type EnforcingReconcileStatusAware (line 32) | type EnforcingReconcileStatusAware interface

FILE: api/v1alpha1/lockedpatch.go
  type PatchSpec (line 25) | type PatchSpec struct
  type TargetObjectReference (line 64) | type TargetObjectReference struct
    method getAPIReourceForGVK (line 95) | func (t *TargetObjectReference) getAPIReourceForGVK(context context.Co...
    method getDynamicClient (line 106) | func (t *TargetObjectReference) getDynamicClient(context context.Conte...
    method GetReferencedObjectWithName (line 127) | func (t *TargetObjectReference) GetReferencedObjectWithName(context co...
    method GetReferencedObject (line 160) | func (t *TargetObjectReference) GetReferencedObject(context context.Co...
    method GetReferencedObjects (line 183) | func (t *TargetObjectReference) GetReferencedObjects(context context.C...
    method IsNamespaced (line 240) | func (t *TargetObjectReference) IsNamespaced(context context.Context) ...
    method IsSelectingMultipleInstances (line 252) | func (t *TargetObjectReference) IsSelectingMultipleInstances(context c...
    method Selects (line 276) | func (t *TargetObjectReference) Selects(context context.Context, obj c...
  function processTemplate (line 400) | func processTemplate(context context.Context, templateString string, par...
  type SourceObjectReference (line 417) | type SourceObjectReference struct
    method GetNameAndNamespace (line 334) | func (s *SourceObjectReference) GetNameAndNamespace(context context.Co...
    method getAPIReourceForGVK (line 349) | func (t *SourceObjectReference) getAPIReourceForGVK(context context.Co...
    method getDynamicClient (line 360) | func (t *SourceObjectReference) getDynamicClient(context context.Conte...
    method GetReferencedObject (line 377) | func (s *SourceObjectReference) GetReferencedObject(context context.Co...

FILE: api/v1alpha1/lockedresource.go
  type LockedResource (line 9) | type LockedResource struct
  type LockedResourceTemplate (line 23) | type LockedResourceTemplate struct

FILE: api/v1alpha1/mycrd_types.go
  type MyCRDSpec (line 27) | type MyCRDSpec struct
  type MyCRDStatus (line 37) | type MyCRDStatus struct
  type MyCRD (line 66) | type MyCRD struct
    method GetConditions (line 54) | func (m *MyCRD) GetConditions() []metav1.Condition {
    method SetConditions (line 58) | func (m *MyCRD) SetConditions(conditions []metav1.Condition) {
  type MyCRDList (line 77) | type MyCRDList struct
  function init (line 83) | func init() {

FILE: api/v1alpha1/templatedenforcingcrd_types.go
  type TemplatedEnforcingCRDSpec (line 27) | type TemplatedEnforcingCRDSpec struct
  type TemplatedEnforcingCRDStatus (line 37) | type TemplatedEnforcingCRDStatus struct
  type TemplatedEnforcingCRD (line 57) | type TemplatedEnforcingCRD struct
    method GetEnforcingReconcileStatus (line 45) | func (m *TemplatedEnforcingCRD) GetEnforcingReconcileStatus() Enforcin...
    method SetEnforcingReconcileStatus (line 49) | func (m *TemplatedEnforcingCRD) SetEnforcingReconcileStatus(reconcileS...
  type TemplatedEnforcingCRDList (line 68) | type TemplatedEnforcingCRDList struct
  function init (line 74) | func init() {

FILE: api/v1alpha1/zz_generated.deepcopy.go
  method DeepCopyInto (line 30) | func (in ConditionMap) DeepCopyInto(out *ConditionMap) {
  method DeepCopy (line 51) | func (in ConditionMap) DeepCopy() ConditionMap {
  method DeepCopyInto (line 61) | func (in Conditions) DeepCopyInto(out *Conditions) {
  method DeepCopy (line 72) | func (in Conditions) DeepCopy() Conditions {
  method DeepCopyInto (line 82) | func (in *EnforcingCRD) DeepCopyInto(out *EnforcingCRD) {
  method DeepCopy (line 91) | func (in *EnforcingCRD) DeepCopy() *EnforcingCRD {
  method DeepCopyObject (line 101) | func (in *EnforcingCRD) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 109) | func (in *EnforcingCRDList) DeepCopyInto(out *EnforcingCRDList) {
  method DeepCopy (line 123) | func (in *EnforcingCRDList) DeepCopy() *EnforcingCRDList {
  method DeepCopyObject (line 133) | func (in *EnforcingCRDList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 141) | func (in *EnforcingCRDSpec) DeepCopyInto(out *EnforcingCRDSpec) {
  method DeepCopy (line 153) | func (in *EnforcingCRDSpec) DeepCopy() *EnforcingCRDSpec {
  method DeepCopyInto (line 163) | func (in *EnforcingCRDStatus) DeepCopyInto(out *EnforcingCRDStatus) {
  method DeepCopy (line 169) | func (in *EnforcingCRDStatus) DeepCopy() *EnforcingCRDStatus {
  method DeepCopyInto (line 179) | func (in *EnforcingPatch) DeepCopyInto(out *EnforcingPatch) {
  method DeepCopy (line 188) | func (in *EnforcingPatch) DeepCopy() *EnforcingPatch {
  method DeepCopyObject (line 198) | func (in *EnforcingPatch) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 206) | func (in *EnforcingPatchList) DeepCopyInto(out *EnforcingPatchList) {
  method DeepCopy (line 220) | func (in *EnforcingPatchList) DeepCopy() *EnforcingPatchList {
  method DeepCopyObject (line 230) | func (in *EnforcingPatchList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 238) | func (in *EnforcingPatchSpec) DeepCopyInto(out *EnforcingPatchSpec) {
  method DeepCopy (line 250) | func (in *EnforcingPatchSpec) DeepCopy() *EnforcingPatchSpec {
  method DeepCopyInto (line 260) | func (in *EnforcingPatchStatus) DeepCopyInto(out *EnforcingPatchStatus) {
  method DeepCopy (line 266) | func (in *EnforcingPatchStatus) DeepCopy() *EnforcingPatchStatus {
  method DeepCopyInto (line 276) | func (in *EnforcingReconcileStatus) DeepCopyInto(out *EnforcingReconcile...
  method DeepCopy (line 332) | func (in *EnforcingReconcileStatus) DeepCopy() *EnforcingReconcileStatus {
  method DeepCopyInto (line 342) | func (in *LockedResource) DeepCopyInto(out *LockedResource) {
  method DeepCopy (line 353) | func (in *LockedResource) DeepCopy() *LockedResource {
  method DeepCopyInto (line 363) | func (in *LockedResourceTemplate) DeepCopyInto(out *LockedResourceTempla...
  method DeepCopy (line 373) | func (in *LockedResourceTemplate) DeepCopy() *LockedResourceTemplate {
  method DeepCopyInto (line 383) | func (in *MyCRD) DeepCopyInto(out *MyCRD) {
  method DeepCopy (line 392) | func (in *MyCRD) DeepCopy() *MyCRD {
  method DeepCopyObject (line 402) | func (in *MyCRD) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 410) | func (in *MyCRDList) DeepCopyInto(out *MyCRDList) {
  method DeepCopy (line 424) | func (in *MyCRDList) DeepCopy() *MyCRDList {
  method DeepCopyObject (line 434) | func (in *MyCRDList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 442) | func (in *MyCRDSpec) DeepCopyInto(out *MyCRDSpec) {
  method DeepCopy (line 447) | func (in *MyCRDSpec) DeepCopy() *MyCRDSpec {
  method DeepCopyInto (line 457) | func (in *MyCRDStatus) DeepCopyInto(out *MyCRDStatus) {
  method DeepCopy (line 469) | func (in *MyCRDStatus) DeepCopy() *MyCRDStatus {
  method DeepCopyInto (line 479) | func (in *PatchSpec) DeepCopyInto(out *PatchSpec) {
  method DeepCopy (line 492) | func (in *PatchSpec) DeepCopy() *PatchSpec {
  method DeepCopyInto (line 502) | func (in *SourceObjectReference) DeepCopyInto(out *SourceObjectReference) {
  method DeepCopy (line 512) | func (in *SourceObjectReference) DeepCopy() *SourceObjectReference {
  method DeepCopyInto (line 522) | func (in *TargetObjectReference) DeepCopyInto(out *TargetObjectReference) {
  method DeepCopy (line 542) | func (in *TargetObjectReference) DeepCopy() *TargetObjectReference {
  method DeepCopyInto (line 552) | func (in *TemplatedEnforcingCRD) DeepCopyInto(out *TemplatedEnforcingCRD) {
  method DeepCopy (line 561) | func (in *TemplatedEnforcingCRD) DeepCopy() *TemplatedEnforcingCRD {
  method DeepCopyObject (line 571) | func (in *TemplatedEnforcingCRD) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 579) | func (in *TemplatedEnforcingCRDList) DeepCopyInto(out *TemplatedEnforcin...
  method DeepCopy (line 593) | func (in *TemplatedEnforcingCRDList) DeepCopy() *TemplatedEnforcingCRDLi...
  method DeepCopyObject (line 603) | func (in *TemplatedEnforcingCRDList) DeepCopyObject() runtime.Object {
  method DeepCopyInto (line 611) | func (in *TemplatedEnforcingCRDSpec) DeepCopyInto(out *TemplatedEnforcin...
  method DeepCopy (line 623) | func (in *TemplatedEnforcingCRDSpec) DeepCopy() *TemplatedEnforcingCRDSp...
  method DeepCopyInto (line 633) | func (in *TemplatedEnforcingCRDStatus) DeepCopyInto(out *TemplatedEnforc...
  method DeepCopy (line 639) | func (in *TemplatedEnforcingCRDStatus) DeepCopy() *TemplatedEnforcingCRD...

FILE: controllers/enforcingcrd_controller.go
  type EnforcingCRDReconciler (line 39) | type EnforcingCRDReconciler struct
    method Reconcile (line 48) | func (r *EnforcingCRDReconciler) Reconcile(context context.Context, re...
    method manageCleanUpLogic (line 105) | func (r *EnforcingCRDReconciler) manageCleanUpLogic(instance *v1alpha1...
    method IsInitialized (line 116) | func (r *EnforcingCRDReconciler) IsInitialized(instance *v1alpha1.Enfo...
    method SetupWithManager (line 136) | func (r *EnforcingCRDReconciler) SetupWithManager(mgr ctrl.Manager) er...

FILE: controllers/enforcingpatch_controller.go
  type EnforcingPatchReconciler (line 37) | type EnforcingPatchReconciler struct
    method Reconcile (line 46) | func (r *EnforcingPatchReconciler) Reconcile(context context.Context, ...
    method IsInitialized (line 88) | func (r *EnforcingPatchReconciler) IsInitialized(instance *v1alpha1.En...
    method SetupWithManager (line 100) | func (r *EnforcingPatchReconciler) SetupWithManager(mgr ctrl.Manager) ...

FILE: controllers/mycrd_controller.go
  constant controllerName (line 33) | controllerName = "MyCRD_controller"
  type MyCRDReconciler (line 38) | type MyCRDReconciler struct
    method Reconcile (line 46) | func (r *MyCRDReconciler) Reconcile(context context.Context, req ctrl....
    method SetupWithManager (line 101) | func (r *MyCRDReconciler) SetupWithManager(mgr ctrl.Manager) error {
    method IsInitialized (line 107) | func (r *MyCRDReconciler) IsInitialized(obj metav1.Object) bool {
    method IsValid (line 121) | func (r *MyCRDReconciler) IsValid(obj metav1.Object) (bool, error) {
    method manageCleanUpLogic (line 132) | func (r *MyCRDReconciler) manageCleanUpLogic(mycrd *v1alpha1.MyCRD) er...
    method manageOperatorLogic (line 136) | func (r *MyCRDReconciler) manageOperatorLogic(mycrd *v1alpha1.MyCRD) e...

FILE: controllers/suite_test.go
  function TestAPIs (line 41) | func TestAPIs(t *testing.T) {

FILE: controllers/templatedenforcingcrd_controller.go
  type TemplatedEnforcingCRDReconciler (line 39) | type TemplatedEnforcingCRDReconciler struct
    method Reconcile (line 48) | func (r *TemplatedEnforcingCRDReconciler) Reconcile(context context.Co...
    method IsInitialized (line 108) | func (r *TemplatedEnforcingCRDReconciler) IsInitialized(instance *v1al...
    method manageCleanUpLogic (line 128) | func (r *TemplatedEnforcingCRDReconciler) manageCleanUpLogic(instance ...
    method SetupWithManager (line 137) | func (r *TemplatedEnforcingCRDReconciler) SetupWithManager(mgr ctrl.Ma...

FILE: main.go
  function init (line 42) | func init() {
  function main (line 49) | func main() {

FILE: pkg/util/apis/conditions.go
  constant ReconcileError (line 9) | ReconcileError = "ReconcileError"
  constant ReconcileErrorReason (line 10) | ReconcileErrorReason = "LastReconcileCycleFailed"
  constant ReconcileSuccess (line 11) | ReconcileSuccess = "ReconcileSuccess"
  constant ReconcileSuccessReason (line 12) | ReconcileSuccessReason = "LastReconcileCycleSucceded"
  type ConditionsAware (line 15) | type ConditionsAware interface
  function AddOrReplaceCondition (line 21) | func AddOrReplaceCondition(c metav1.Condition, conditions []metav1.Condi...
  function GetCondition (line 33) | func GetCondition(conditionType string, conditions []metav1.Condition) (...
  function GetLastCondition (line 43) | func GetLastCondition(conditions []metav1.Condition) (metav1.Condition, ...
  function IsErrorCondition (line 59) | func IsErrorCondition(condition metav1.Condition) bool {

FILE: pkg/util/apis/key.go
  function GetKeyLong (line 15) | func GetKeyLong(obj metav1.Object) string {
  function GetKeyShort (line 27) | func GetKeyShort(obj metav1.Object) string {

FILE: pkg/util/crud/crudutils.go
  function CreateOrUpdateResource (line 20) | func CreateOrUpdateResource(context context.Context, owner client.Object...
  function CreateOrUpdateResources (line 62) | func CreateOrUpdateResources(context context.Context, owner client.Objec...
  function CreateOrUpdateUnstructuredResources (line 74) | func CreateOrUpdateUnstructuredResources(context context.Context, owner ...
  function DeleteResourceIfExists (line 86) | func DeleteResourceIfExists(context context.Context, obj client.Object) ...
  function DeleteResourcesIfExist (line 99) | func DeleteResourcesIfExist(context context.Context, objs []client.Objec...
  function DeleteUnstructuredResources (line 111) | func DeleteUnstructuredResources(context context.Context, objs []unstruc...
  function CreateResourceIfNotExists (line 125) | func CreateResourceIfNotExists(context context.Context, owner client.Obj...
  function CreateResourcesIfNotExist (line 145) | func CreateResourcesIfNotExist(context context.Context, owner client.Obj...
  function CreateUnstructuredResourcesIfNotExist (line 157) | func CreateUnstructuredResourcesIfNotExist(context context.Context, owne...
  function CreateOrUpdateTemplatedResources (line 169) | func CreateOrUpdateTemplatedResources(context context.Context, owner cli...
  function CreateIfNotExistTemplatedResources (line 187) | func CreateIfNotExistTemplatedResources(context context.Context, owner c...
  function DeleteTemplatedResources (line 205) | func DeleteTemplatedResources(context context.Context, data interface{},...

FILE: pkg/util/discoveryclient/discoveryclientutils.go
  function GetDiscoveryClient (line 17) | func GetDiscoveryClient(context context.Context) (*discovery.DiscoveryCl...
  function IsGVKDefined (line 24) | func IsGVKDefined(context context.Context, GVK schema.GroupVersionKind) ...
  function GetAPIResourceForGVK (line 29) | func GetAPIResourceForGVK(context context.Context, GVK schema.GroupVersi...
  function IsGVKNamespaced (line 55) | func IsGVKNamespaced(context context.Context, GVK schema.GroupVersionKin...
  function IsUnstructuredDefined (line 65) | func IsUnstructuredDefined(context context.Context, obj *unstructured.Un...
  function IsUnstructuredNamespaced (line 71) | func IsUnstructuredNamespaced(context context.Context, obj *unstructured...

FILE: pkg/util/dynamicclient/dynamicclientutils.go
  function GetDynamicClientOnUnstructured (line 23) | func GetDynamicClientOnUnstructured(context context.Context, obj *unstru...
  function GetDynamicClientForAPIResource (line 43) | func GetDynamicClientForAPIResource(context context.Context, resource *m...
  function getDynamicClientForGVR (line 51) | func getDynamicClientForGVR(context context.Context, gvr schema.GroupVer...
  function GetDynamicClientForGVK (line 65) | func GetDynamicClientForGVK(context context.Context, gvk schema.GroupVer...
  function getAPIReourceForGVK (line 80) | func getAPIReourceForGVK(context context.Context, gvk schema.GroupVersio...
  function SetIndexField (line 107) | func SetIndexField(context context.Context, cache cache.Cache, obj clien...

FILE: pkg/util/finalizer.go
  function IsBeingDeleted (line 25) | func IsBeingDeleted(obj client.Object) bool {
  function HasFinalizer (line 31) | func HasFinalizer(obj client.Object, finalizer string) bool {
  function AddFinalizer (line 37) | func AddFinalizer(obj client.Object, finalizer string) {
  function RemoveFinalizer (line 43) | func RemoveFinalizer(obj client.Object, finalizer string) {

FILE: pkg/util/lockedresourcecontroller/enforcing-reconciler.go
  type EnforcingReconciler (line 28) | type EnforcingReconciler struct
    method GetStatusChangeChannel (line 59) | func (er *EnforcingReconciler) GetStatusChangeChannel() <-chan event.G...
    method removeLockedResourceManager (line 63) | func (er *EnforcingReconciler) removeLockedResourceManager(instance cl...
    method getLockedResourceManager (line 69) | func (er *EnforcingReconciler) getLockedResourceManager(instance clien...
    method UpdateLockedResources (line 90) | func (er *EnforcingReconciler) UpdateLockedResources(context context.C...
    method UpdateLockedResourcesWithRestConfig (line 101) | func (er *EnforcingReconciler) UpdateLockedResourcesWithRestConfig(con...
    method ManageError (line 146) | func (er *EnforcingReconciler) ManageError(context context.Context, in...
    method ManageSuccess (line 179) | func (er *EnforcingReconciler) ManageSuccess(context context.Context, ...
    method GetLockedResourceStatuses (line 210) | func (er *EnforcingReconciler) GetLockedResourceStatuses(instance clie...
    method GetLockedPatchStatuses (line 231) | func (er *EnforcingReconciler) GetLockedPatchStatuses(instance client....
    method Terminate (line 258) | func (er *EnforcingReconciler) Terminate(instance client.Object, delet...
  function NewEnforcingReconciler (line 42) | func NewEnforcingReconciler(client client.Client, scheme *runtime.Scheme...
  function NewFromManager (line 54) | func NewFromManager(mgr manager.Manager, recorderName string, clusterWat...
  function getToBeDeletdResources (line 126) | func getToBeDeletdResources(neededResources []lockedresource.LockedResou...

FILE: pkg/util/lockedresourcecontroller/locked-resource-manager.go
  type LockedResourceManager (line 36) | type LockedResourceManager struct
    method GetResources (line 68) | func (lrm *LockedResourceManager) GetResources() []lockedresource.Lock...
    method GetPatches (line 73) | func (lrm *LockedResourceManager) GetPatches() []lockedpatch.LockedPat...
    method SetResources (line 78) | func (lrm *LockedResourceManager) SetResources(resources []lockedresou...
    method SetPatches (line 92) | func (lrm *LockedResourceManager) SetPatches(patches []lockedpatch.Loc...
    method IsStarted (line 117) | func (lrm *LockedResourceManager) IsStarted() bool {
    method Start (line 122) | func (lrm *LockedResourceManager) Start(ctx context.Context, config *r...
    method Stop (line 175) | func (lrm *LockedResourceManager) Stop(deleteResources bool) error {
    method scanNamespaces (line 187) | func (lrm *LockedResourceManager) scanNamespaces() []string {
    method Restart (line 213) | func (lrm *LockedResourceManager) Restart(ctx context.Context, resourc...
    method IsSameResources (line 240) | func (lrm *LockedResourceManager) IsSameResources(resources []lockedre...
    method IsSamePatches (line 255) | func (lrm *LockedResourceManager) IsSamePatches(patches []lockedpatch....
    method deleteResources (line 284) | func (lrm *LockedResourceManager) deleteResources(context context.Cont...
    method GetResourceReconcilers (line 300) | func (lrm *LockedResourceManager) GetResourceReconcilers() []*LockedRe...
    method validateLockedResources (line 307) | func (lrm *LockedResourceManager) validateLockedResources(lockedResour...
    method GetPatchReconcilers (line 368) | func (lrm *LockedResourceManager) GetPatchReconcilers() []*LockedPatch...
    method validateLockedPatches (line 375) | func (lrm *LockedResourceManager) validateLockedPatches(patches []lock...
  function NewLockedResourceManager (line 55) | func NewLockedResourceManager(config *rest.Config, options manager.Optio...

FILE: pkg/util/lockedresourcecontroller/lockedpatch/lockedpatch.go
  type LockedPatch (line 18) | type LockedPatch struct
    method GetKey (line 28) | func (lp *LockedPatch) GetKey() string {
  function GetLockedPatchMap (line 33) | func GetLockedPatchMap(lockedPatches []LockedPatch) (map[string]LockedPa...
  function GetLockedPatchesFromLockedPatcheSet (line 43) | func GetLockedPatchesFromLockedPatcheSet(lockedPatchSet *strset.Set, loc...
  function GetLockedPatches (line 52) | func GetLockedPatches(patches map[string]utilsapi.PatchSpec, config *res...

FILE: pkg/util/lockedresourcecontroller/lockedresource/lockedresource.go
  type LockedResource (line 23) | type LockedResource struct
    method GetKey (line 40) | func (lr *LockedResource) GetKey() string {
  function AsListOfUnstructured (line 31) | func AsListOfUnstructured(lockedResources []LockedResource) []unstructur...
  function GetLockedResources (line 50) | func GetLockedResources(resources []utilsapi.LockedResource) ([]LockedRe...
  function GetLockedResourcesFromTemplates (line 75) | func GetLockedResourcesFromTemplates(resources []utilsapi.LockedResource...
  function GetLockedResourcesFromTemplatesWithRestConfig (line 81) | func GetLockedResourcesFromTemplatesWithRestConfig(resources []utilsapi....
  function getTemplate (line 107) | func getTemplate(resource *utilsapi.LockedResourceTemplate, config *rest...
  function GetResources (line 128) | func GetResources(lockedResources []LockedResource) []client.Object {

FILE: pkg/util/lockedresourcecontroller/lockedresource/lockedresourceset/lockedresourceset.go
  type Set (line 22) | type Set struct
    method Add (line 40) | func (s *Set) Add(items ...lockedresource.LockedResource) {
    method Remove (line 48) | func (s *Set) Remove(items ...lockedresource.LockedResource) {
    method Pop (line 56) | func (s *Set) Pop() lockedresource.LockedResource {
    method Pop2 (line 68) | func (s *Set) Pop2() (lockedresource.LockedResource, bool) {
    method Has (line 78) | func (s *Set) Has(items ...lockedresource.LockedResource) bool {
    method HasAny (line 91) | func (s *Set) HasAny(items ...lockedresource.LockedResource) bool {
    method Size (line 102) | func (s *Set) Size() int {
    method Clear (line 107) | func (s *Set) Clear() {
    method IsEmpty (line 112) | func (s *Set) IsEmpty() bool {
    method IsEqual (line 117) | func (s *Set) IsEqual(t *Set) bool {
    method IsSubset (line 133) | func (s *Set) IsSubset(t *Set) bool {
    method IsSuperset (line 149) | func (s *Set) IsSuperset(t *Set) bool {
    method Each (line 156) | func (s *Set) Each(f func(item lockedresource.LockedResource) bool) {
    method Copy (line 165) | func (s *Set) Copy() *Set {
    method String (line 174) | func (s *Set) String() string {
    method List (line 184) | func (s *Set) List() []lockedresource.LockedResource {
    method Merge (line 194) | func (s *Set) Merge(t *Set) {
    method Separate (line 202) | func (s *Set) Separate(t *Set) {
  function New (line 27) | func New(ts ...lockedresource.LockedResource) *Set {
  function NewWithSize (line 34) | func NewWithSize(size int) *Set {
  function Union (line 210) | func Union(sets ...*Set) *Set {
  function Difference (line 237) | func Difference(set1 *Set, sets ...*Set) *Set {
  function Intersection (line 247) | func Intersection(sets ...*Set) *Set {
  function SymmetricDifference (line 276) | func SymmetricDifference(s *Set, t *Set) *Set {

FILE: pkg/util/lockedresourcecontroller/lockedresource/patch.go
  function FilterOutPaths (line 11) | func FilterOutPaths(obj *unstructured.Unstructured, jsonPaths []string) ...
  type Patch (line 53) | type Patch struct
  function createPatchesFromJSONPaths (line 58) | func createPatchesFromJSONPaths(jsonPaths []string) ([][]byte, error) {
  function getMergePathFromJSONPath (line 77) | func getMergePathFromJSONPath(jsonPath string) string {

FILE: pkg/util/lockedresourcecontroller/patch-reconciler.go
  type LockedPatchReconciler (line 39) | type LockedPatchReconciler struct
    method Reconcile (line 438) | func (lpr *LockedPatchReconciler) Reconcile(ctx context.Context, reque...
    method GetKey (line 492) | func (lpr *LockedPatchReconciler) GetKey() string {
    method manageError (line 522) | func (lpr *LockedPatchReconciler) manageError(target client.Object, er...
    method manageErrorNoTarget (line 535) | func (lpr *LockedPatchReconciler) manageErrorNoTarget(err error) (reco...
    method manageSuccess (line 548) | func (lpr *LockedPatchReconciler) manageSuccess(target client.Object) ...
    method setStatus (line 560) | func (lpr *LockedPatchReconciler) setStatus(key string, conditions []m...
    method GetStatus (line 572) | func (lpr *LockedPatchReconciler) GetStatus() map[string][]metav1.Cond...
  function NewLockedPatchReconciler (line 50) | func NewLockedPatchReconciler(mgr manager.Manager, patch lockedpatch.Loc...
  function sourceObjectRefToRuntimeType (line 117) | func sourceObjectRefToRuntimeType(objref *utilsapi.SourceObjectReference...
  function targetObjectRefToRuntimeType (line 124) | func targetObjectRefToRuntimeType(objref *utilsapi.TargetObjectReference...
  type enqueueRequestForPatch (line 131) | type enqueueRequestForPatch struct
    method Create (line 139) | func (e *enqueueRequestForPatch) Create(ctx context.Context, evt event...
    method Update (line 212) | func (e *enqueueRequestForPatch) Update(ctx context.Context, evt event...
    method Delete (line 275) | func (e *enqueueRequestForPatch) Delete(ctx context.Context, evt event...
    method Generic (line 279) | func (e *enqueueRequestForPatch) Generic(ctx context.Context, evt even...
  type sourceReferenceModifiedPredicate (line 282) | type sourceReferenceModifiedPredicate struct
    method Update (line 290) | func (p *sourceReferenceModifiedPredicate) Update(e event.UpdateEvent)...
    method Create (line 298) | func (p *sourceReferenceModifiedPredicate) Create(e event.CreateEvent)...
    method isRelevant (line 304) | func (p *sourceReferenceModifiedPredicate) isRelevant(obj client.Objec...
    method Delete (line 335) | func (p *sourceReferenceModifiedPredicate) Delete(e event.DeleteEvent)...
    method Generic (line 340) | func (p *sourceReferenceModifiedPredicate) Generic(e event.GenericEven...
  type targetReferenceModifiedPredicate (line 345) | type targetReferenceModifiedPredicate struct
    method Update (line 352) | func (p *targetReferenceModifiedPredicate) Update(e event.UpdateEvent)...
    method Create (line 369) | func (p *targetReferenceModifiedPredicate) Create(e event.CreateEvent)...
    method Delete (line 382) | func (p *targetReferenceModifiedPredicate) Delete(e event.DeleteEvent)...
    method Generic (line 387) | func (p *targetReferenceModifiedPredicate) Generic(e event.GenericEven...
  function compareObjectsWithoutIgnoredFields (line 393) | func compareObjectsWithoutIgnoredFields(changedObjSrc runtime.Object, or...
  function compareSourceObjects (line 408) | func compareSourceObjects(ctx context.Context, sourceObjectReference *ut...
  function getSubMapFromObject (line 496) | func getSubMapFromObject(ctx context.Context, obj *unstructured.Unstruct...

FILE: pkg/util/lockedresourcecontroller/resource-reconciler.go
  type LockedResourceReconciler (line 38) | type LockedResourceReconciler struct
    method Reconcile (line 112) | func (lor *LockedResourceReconciler) Reconcile(ctx context.Context, re...
    method isEqual (line 168) | func (lor *LockedResourceReconciler) isEqual(instance *unstructured.Un...
    method logDiff (line 180) | func (lor *LockedResourceReconciler) logDiff(instance *unstructured.Un...
    method manageError (line 250) | func (lor *LockedResourceReconciler) manageError(instance *unstructure...
    method manageErrorNoInstance (line 269) | func (lor *LockedResourceReconciler) manageErrorNoInstance(err error) ...
    method manageSuccess (line 282) | func (lor *LockedResourceReconciler) manageSuccess(instance *unstructu...
    method manageSuccessNoInstance (line 294) | func (lor *LockedResourceReconciler) manageSuccessNoInstance() (reconc...
    method setStatus (line 306) | func (lor *LockedResourceReconciler) setStatus(status []metav1.Conditi...
    method GetStatus (line 318) | func (lor *LockedResourceReconciler) GetStatus() []metav1.Condition {
  function NewLockedObjectReconciler (line 51) | func NewLockedObjectReconciler(mgr manager.Manager, object unstructured....
  type resourceModifiedPredicate (line 205) | type resourceModifiedPredicate struct
    method Update (line 213) | func (p *resourceModifiedPredicate) Update(e event.UpdateEvent) bool {
    method Create (line 220) | func (p *resourceModifiedPredicate) Create(e event.CreateEvent) bool {
    method Delete (line 227) | func (p *resourceModifiedPredicate) Delete(e event.DeleteEvent) bool {

FILE: pkg/util/owner.go
  function IsOwner (line 24) | func IsOwner(owner, owned metav1.Object) bool {

FILE: pkg/util/predicates.go
  type ResourceGenerationOrFinalizerChangedPredicate (line 27) | type ResourceGenerationOrFinalizerChangedPredicate struct
    method Update (line 32) | func (ResourceGenerationOrFinalizerChangedPredicate) Update(e event.Up...

FILE: pkg/util/reconciler.go
  type ReconcilerBase (line 52) | type ReconcilerBase struct
    method IsValid (line 76) | func (r *ReconcilerBase) IsValid(obj metav1.Object) (bool, error) {
    method IsInitialized (line 81) | func (r *ReconcilerBase) IsInitialized(obj metav1.Object) bool {
    method Reconcile (line 86) | func (r *ReconcilerBase) Reconcile(request reconcile.Request) (reconci...
    method GetClient (line 91) | func (r *ReconcilerBase) GetClient() client.Client {
    method GetRestConfig (line 96) | func (r *ReconcilerBase) GetRestConfig() *rest.Config {
    method GetRecorder (line 101) | func (r *ReconcilerBase) GetRecorder() record.EventRecorder {
    method GetScheme (line 106) | func (r *ReconcilerBase) GetScheme() *runtime.Scheme {
    method GetDiscoveryClient (line 111) | func (r *ReconcilerBase) GetDiscoveryClient() (*discovery.DiscoveryCli...
    method CreateOrUpdateResource (line 118) | func (r *ReconcilerBase) CreateOrUpdateResource(context context.Contex...
    method CreateOrUpdateResources (line 158) | func (r *ReconcilerBase) CreateOrUpdateResources(context context.Conte...
    method CreateOrUpdateUnstructuredResources (line 169) | func (r *ReconcilerBase) CreateOrUpdateUnstructuredResources(context c...
    method DeleteResourceIfExists (line 180) | func (r *ReconcilerBase) DeleteResourceIfExists(context context.Contex...
    method DeleteResourcesIfExist (line 191) | func (r *ReconcilerBase) DeleteResourcesIfExist(context context.Contex...
    method DeleteUnstructuredResources (line 202) | func (r *ReconcilerBase) DeleteUnstructuredResources(context context.C...
    method CreateResourceIfNotExists (line 215) | func (r *ReconcilerBase) CreateResourceIfNotExists(context context.Con...
    method CreateResourcesIfNotExist (line 233) | func (r *ReconcilerBase) CreateResourcesIfNotExist(context context.Con...
    method CreateUnstructuredResourcesIfNotExist (line 244) | func (r *ReconcilerBase) CreateUnstructuredResourcesIfNotExist(context...
    method CreateOrUpdateTemplatedResources (line 255) | func (r *ReconcilerBase) CreateOrUpdateTemplatedResources(context cont...
    method CreateIfNotExistTemplatedResources (line 272) | func (r *ReconcilerBase) CreateIfNotExistTemplatedResources(context co...
    method DeleteTemplatedResources (line 289) | func (r *ReconcilerBase) DeleteTemplatedResources(context context.Cont...
    method ManageOutcomeWithRequeue (line 306) | func (r *ReconcilerBase) ManageOutcomeWithRequeue(context context.Cont...
    method ManageErrorWithRequeue (line 317) | func (r *ReconcilerBase) ManageErrorWithRequeue(context context.Contex...
    method ManageError (line 345) | func (r *ReconcilerBase) ManageError(context context.Context, obj clie...
    method ManageSuccessWithRequeue (line 350) | func (r *ReconcilerBase) ManageSuccessWithRequeue(context context.Cont...
    method ManageSuccess (line 373) | func (r *ReconcilerBase) ManageSuccess(context context.Context, obj cl...
    method GetDirectClient (line 378) | func (r *ReconcilerBase) GetDirectClient() (client.Client, error) {
    method GetDirectClientWithSchemeBuilders (line 383) | func (r *ReconcilerBase) GetDirectClientWithSchemeBuilders(addToScheme...
    method GetAPIReader (line 397) | func (r *ReconcilerBase) GetAPIReader() client.Reader {
    method GetOperatorNamespace (line 403) | func (r *ReconcilerBase) GetOperatorNamespace() (string, error) {
  function NewReconcilerBase (line 60) | func NewReconcilerBase(client client.Client, scheme *runtime.Scheme, res...
  function NewFromManager (line 71) | func NewFromManager(mgr manager.Manager, recorder record.EventRecorder) ...

FILE: pkg/util/stoppablemanager/stoppable-manager.go
  type StoppableManager (line 15) | type StoppableManager struct
    method Stop (line 22) | func (sm *StoppableManager) Stop() {
    method Start (line 33) | func (sm *StoppableManager) Start(parentCtx context.Context) {
    method IsStarted (line 61) | func (sm *StoppableManager) IsStarted() bool {
  function NewStoppableManager (line 50) | func NewStoppableManager(config *rest.Config, options manager.Options) (...

FILE: pkg/util/templates/advanced-funcmap.go
  function AdvancedTemplateFuncMap (line 43) | func AdvancedTemplateFuncMap(config *rest.Config, logger logr.Logger) te...
  function toYAML (line 90) | func toYAML(v interface{}) string {
  function fromYAML (line 105) | func fromYAML(str string) map[string]interface{} {
  function fromYAMLArray (line 120) | func fromYAMLArray(str string) []interface{} {
  function toTOML (line 133) | func toTOML(v interface{}) string {
  function toJSON (line 147) | func toJSON(v interface{}) string {
  function fromJSON (line 162) | func fromJSON(str string) map[string]interface{} {
  function fromJSONArray (line 177) | func fromJSONArray(str string) []interface{} {
  function NewLookupFunction (line 189) | func NewLookupFunction(config *rest.Config, logger logr.Logger) lookupFu...

FILE: pkg/util/templates/templates.go
  function ProcessTemplate (line 33) | func ProcessTemplate(context context.Context, data interface{}, template...
  function ProcessTemplateArray (line 59) | func ProcessTemplateArray(context context.Context, data interface{}, tem...
  function ValidateUnstructured (line 110) | func ValidateUnstructured(context context.Context, obj *unstructured.Uns...
  function IsJSONArray (line 126) | func IsJSONArray(data []byte) bool {
Condensed preview — 121 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (531K chars).
[
  {
    "path": ".github/workflows/pr.yaml",
    "chars": 6236,
    "preview": "name: pull request\non:\n  pull_request:\n    branches:\n      - master\n      - main\n\njobs:\n  setup:\n    runs-on: ubuntu-lat"
  },
  {
    "path": ".github/workflows/push.yaml",
    "chars": 6780,
    "preview": "name: push\non:\n  push:\n    branches:\n      - main\n      - master\n    tags:\n      - v*\n\njobs:\n  setup:\n    runs-on: ubunt"
  },
  {
    "path": ".gitignore",
    "chars": 383,
    "preview": "\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\nbin\n\n# Test binary, build with `go test -c`\n*.test\n"
  },
  {
    "path": "Dockerfile",
    "chars": 802,
    "preview": "# Build the manager binary\nFROM golang:1.18 as builder\n\nWORKDIR /workspace\n# Copy the Go Modules manifests\nCOPY go.mod g"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "Makefile",
    "chars": 11150,
    "preview": "# VERSION defines the project version for the bundle.\n# Update this value when you upgrade the version of your project.\n"
  },
  {
    "path": "PROJECT",
    "chars": 822,
    "preview": "domain: example.io\nlayout:\n- go.kubebuilder.io/v3\nprojectName: operator-utils\nrepo: github.com/redhat-cop/operator-utils"
  },
  {
    "path": "README.md",
    "chars": 19747,
    "preview": "# Operator Utility Library\n\n![build status](https://github.com/redhat-cop/operator-utils/workflows/push/badge.svg)\n[![Go"
  },
  {
    "path": "api/v1alpha1/enforcingcrd_types.go",
    "chars": 2778,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "api/v1alpha1/enforcingpatch_types.go",
    "chars": 2729,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "api/v1alpha1/enforcingreconcilerstatus.go",
    "chars": 1480,
    "preview": "package v1alpha1\n\nimport metav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n// +listType=map\n// +listMapKey=type\ntype Condit"
  },
  {
    "path": "api/v1alpha1/groupversion_info.go",
    "chars": 1238,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "api/v1alpha1/lockedpatch.go",
    "chars": 17910,
    "preview": "package v1alpha1\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"text/template\"\n\n\t\"github.com/redhat-cop/operator-utils/pkg/ut"
  },
  {
    "path": "api/v1alpha1/lockedresource.go",
    "chars": 1234,
    "preview": "package v1alpha1\n\nimport (\n\t\"k8s.io/apimachinery/pkg/runtime\"\n)\n\n// LockedResource represents a resource to be enforced "
  },
  {
    "path": "api/v1alpha1/mycrd_types.go",
    "chars": 2809,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "api/v1alpha1/templatedenforcingcrd_types.go",
    "chars": 2856,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "api/v1alpha1/zz_generated.deepcopy.go",
    "chars": 19052,
    "preview": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n/*\n\n\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "ci.Dockerfile",
    "chars": 119,
    "preview": "FROM registry.access.redhat.com/ubi8/ubi-minimal\nWORKDIR /\nCOPY bin/manager .\nUSER 65532:65532\n\nENTRYPOINT [\"/manager\"]"
  },
  {
    "path": "config/certmanager/certificate.yaml",
    "chars": 943,
    "preview": "# The following manifests contain a self-signed issuer CR and a certificate CR.\n# More document can be found at https://"
  },
  {
    "path": "config/certmanager/kustomization.yaml",
    "chars": 70,
    "preview": "resources:\n- certificate.yaml\n\nconfigurations:\n- kustomizeconfig.yaml\n"
  },
  {
    "path": "config/certmanager/kustomizeconfig.yaml",
    "chars": 391,
    "preview": "# This configuration is for teaching kustomize how to update name ref and var substitution \nnameReference:\n- kind: Issue"
  },
  {
    "path": "config/crd/bases/operator-utils.example.io_enforcingcrds.yaml",
    "chars": 16585,
    "preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubeb"
  },
  {
    "path": "config/crd/bases/operator-utils.example.io_enforcingpatches.yaml",
    "chars": 27198,
    "preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubeb"
  },
  {
    "path": "config/crd/bases/operator-utils.example.io_mycrds.yaml",
    "chars": 6454,
    "preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubeb"
  },
  {
    "path": "config/crd/bases/operator-utils.example.io_templatedenforcingcrds.yaml",
    "chars": 16729,
    "preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubeb"
  },
  {
    "path": "config/crd/kustomization.yaml",
    "chars": 1366,
    "preview": "# This kustomization.yaml is not intended to be run by itself,\n# since it depends on service name and namespace that are"
  },
  {
    "path": "config/crd/kustomizeconfig.yaml",
    "chars": 474,
    "preview": "# This file is for teaching kustomize how to substitute name and namespace reference in CRD\nnameReference:\n- kind: Servi"
  },
  {
    "path": "config/crd/patches/cainjection_in_enforcingcrds.yaml",
    "chars": 352,
    "preview": "# The following patch adds a directive for certmanager to inject CA into the CRD\n# CRD conversion requires k8s 1.13 or l"
  },
  {
    "path": "config/crd/patches/cainjection_in_enforcingpatches.yaml",
    "chars": 355,
    "preview": "# The following patch adds a directive for certmanager to inject CA into the CRD\n# CRD conversion requires k8s 1.13 or l"
  },
  {
    "path": "config/crd/patches/cainjection_in_mycrds.yaml",
    "chars": 345,
    "preview": "# The following patch adds a directive for certmanager to inject CA into the CRD\n# CRD conversion requires k8s 1.13 or l"
  },
  {
    "path": "config/crd/patches/cainjection_in_templatedenforcingcrds.yaml",
    "chars": 361,
    "preview": "# The following patch adds a directive for certmanager to inject CA into the CRD\n# CRD conversion requires k8s 1.13 or l"
  },
  {
    "path": "config/crd/patches/webhook_in_enforcingcrds.yaml",
    "chars": 636,
    "preview": "# The following patch enables conversion webhook for CRD\n# CRD conversion requires k8s 1.13 or later.\napiVersion: apiext"
  },
  {
    "path": "config/crd/patches/webhook_in_enforcingpatches.yaml",
    "chars": 639,
    "preview": "# The following patch enables conversion webhook for CRD\n# CRD conversion requires k8s 1.13 or later.\napiVersion: apiext"
  },
  {
    "path": "config/crd/patches/webhook_in_mycrds.yaml",
    "chars": 629,
    "preview": "# The following patch enables conversion webhook for CRD\n# CRD conversion requires k8s 1.13 or later.\napiVersion: apiext"
  },
  {
    "path": "config/crd/patches/webhook_in_templatedenforcingcrds.yaml",
    "chars": 645,
    "preview": "# The following patch enables conversion webhook for CRD\n# CRD conversion requires k8s 1.13 or later.\napiVersion: apiext"
  },
  {
    "path": "config/default/kustomization.yaml",
    "chars": 2700,
    "preview": "# Adds namespace to all resources.\nnamespace: operator-utils\n\n# Value of this field is prepended to the\n# names of all r"
  },
  {
    "path": "config/default/manager_auth_proxy_patch.yaml",
    "chars": 1241,
    "preview": "# This patch inject a sidecar container which is a HTTP proxy for the \n# controller manager, it performs RBAC authorizat"
  },
  {
    "path": "config/default/manager_webhook_patch.yaml",
    "chars": 508,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: controller-manager\n  namespace: system\nspec:\n  template:\n    spec"
  },
  {
    "path": "config/default/webhookcainjection_patch.yaml",
    "chars": 625,
    "preview": "# This patch add annotation to admission webhook config and\n# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_N"
  },
  {
    "path": "config/helmchart/.helmignore",
    "chars": 349,
    "preview": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation"
  },
  {
    "path": "config/helmchart/Chart.yaml.tpl",
    "chars": 272,
    "preview": "apiVersion: v1\nname: operator-utils\nversion: ${version}\nappVersion: ${version}\ndescription: Helm chart that deploys oper"
  },
  {
    "path": "config/helmchart/kustomization.yaml",
    "chars": 725,
    "preview": "# Adds namespace to all resources.\nnamespace: release-namespace\n\n# Value of this field is prepended to the\n# names of al"
  },
  {
    "path": "config/helmchart/templates/_helpers.tpl",
    "chars": 1890,
    "preview": "{{/* vim: set filetype=mustache: */}}\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"operator-utils.name\" -}}\n{{- d"
  },
  {
    "path": "config/helmchart/templates/manager.yaml",
    "chars": 2287,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: {{ include \"operator-utils.fullname\" . }}\n  labels:\n    {{- inclu"
  },
  {
    "path": "config/helmchart/values.yaml.tpl",
    "chars": 982,
    "preview": "# Default values for helm-try.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\nr"
  },
  {
    "path": "config/local-development/kustomization.yaml",
    "chars": 451,
    "preview": "# Adds namespace to all resources.\nnamespace: operator-utils-operator-local\n\n# Value of this field is prepended to the\n#"
  },
  {
    "path": "config/manager/kustomization.yaml",
    "chars": 185,
    "preview": "resources:\n- manager.yaml\napiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nimages:\n- name: controller\n  n"
  },
  {
    "path": "config/manager/manager.yaml",
    "chars": 825,
    "preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n  labels:\n    operator: operator-utils-operator\n  name: system\n---\napiVersion: "
  },
  {
    "path": "config/manifests/bases/operator-utils.clusterserviceversion.yaml",
    "chars": 68410,
    "preview": "apiVersion: operators.coreos.com/v1alpha1\nkind: ClusterServiceVersion\nmetadata:\n  annotations:\n    alm-examples: '[]'\n  "
  },
  {
    "path": "config/manifests/kustomization.yaml",
    "chars": 52,
    "preview": "resources:\n- ../default\n- ../samples\n- ../scorecard\n"
  },
  {
    "path": "config/prometheus/kustomization.yaml",
    "chars": 66,
    "preview": "resources:\n- monitor.yaml\n\nconfigurations:\n- kustomizeconfig.yaml\n"
  },
  {
    "path": "config/prometheus/kustomizeconfig.yaml",
    "chars": 85,
    "preview": "---\nvarReference:\n- path: spec/endpoints/tlsConfig/serverName\n  kind: ServiceMonitor "
  },
  {
    "path": "config/prometheus/monitor.yaml",
    "chars": 616,
    "preview": "\n# Prometheus Monitor Service (Metrics)\napiVersion: monitoring.coreos.com/v1\nkind: ServiceMonitor\nmetadata:\n  labels:\n  "
  },
  {
    "path": "config/rbac/auth_proxy_client_clusterrole.yaml",
    "chars": 148,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: metrics-reader\nrules:\n- nonResourceURLs: [\""
  },
  {
    "path": "config/rbac/auth_proxy_role.yaml",
    "chars": 280,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: proxy-role\nrules:\n- apiGroups: [\"authentica"
  },
  {
    "path": "config/rbac/auth_proxy_role_binding.yaml",
    "chars": 268,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: proxy-rolebinding\nroleRef:\n  apiGrou"
  },
  {
    "path": "config/rbac/auth_proxy_service.yaml",
    "chars": 366,
    "preview": "apiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    operator: operator-utils-operator\n  annotations:\n    service.alpha."
  },
  {
    "path": "config/rbac/enforcingcrd_editor_role.yaml",
    "chars": 411,
    "preview": "# permissions for end users to edit enforcingcrds.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n"
  },
  {
    "path": "config/rbac/enforcingcrd_viewer_role.yaml",
    "chars": 368,
    "preview": "# permissions for end users to view enforcingcrds.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n"
  },
  {
    "path": "config/rbac/enforcingpatch_editor_role.yaml",
    "chars": 422,
    "preview": "# permissions for end users to edit enforcingpatches.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadat"
  },
  {
    "path": "config/rbac/enforcingpatch_viewer_role.yaml",
    "chars": 379,
    "preview": "# permissions for end users to view enforcingpatches.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadat"
  },
  {
    "path": "config/rbac/kustomization.yaml",
    "chars": 381,
    "preview": "resources:\n- role.yaml\n- role_binding.yaml\n- leader_election_role.yaml\n- leader_election_role_binding.yaml\n# Comment the"
  },
  {
    "path": "config/rbac/leader_election_role.yaml",
    "chars": 571,
    "preview": "# permissions to do leader election.\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: leader-electi"
  },
  {
    "path": "config/rbac/leader_election_role_binding.yaml",
    "chars": 274,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: leader-election-rolebinding\nroleRef:\n  apiG"
  },
  {
    "path": "config/rbac/mycrd_editor_role.yaml",
    "chars": 383,
    "preview": "# permissions for end users to edit mycrds.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name:"
  },
  {
    "path": "config/rbac/mycrd_viewer_role.yaml",
    "chars": 340,
    "preview": "# permissions for end users to view mycrds.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name:"
  },
  {
    "path": "config/rbac/role.yaml",
    "chars": 1284,
    "preview": "---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  creationTimestamp: null\n  name: manager-role\n"
  },
  {
    "path": "config/rbac/role_binding.yaml",
    "chars": 272,
    "preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: manager-rolebinding\nroleRef:\n  apiGr"
  },
  {
    "path": "config/rbac/templatedenforcingcrd_editor_role.yaml",
    "chars": 447,
    "preview": "# permissions for end users to edit templatedenforcingcrds.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nm"
  },
  {
    "path": "config/rbac/templatedenforcingcrd_viewer_role.yaml",
    "chars": 404,
    "preview": "# permissions for end users to view templatedenforcingcrds.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nm"
  },
  {
    "path": "config/samples/kustomization.yaml",
    "chars": 309,
    "preview": "## Append samples you want in your CSV to this file as resources ##\nresources:\n- operator-utils_v1alpha1_mycrd.yaml\n- op"
  },
  {
    "path": "config/samples/operator-utils_v1alpha1_enforcingcrd.yaml",
    "chars": 788,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingCRD\nmetadata:\n  name: example-enforcingcrd\nspec:\n  resourc"
  },
  {
    "path": "config/samples/operator-utils_v1alpha1_enforcingpatch.yaml",
    "chars": 660,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingPatch\nmetadata:\n  name: test-field-patch\nspec:\n  patches:\n"
  },
  {
    "path": "config/samples/operator-utils_v1alpha1_mycrd.yaml",
    "chars": 167,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: MyCRD\nmetadata:\n  name: example-mycrd\nspec:\n  # Add fields here\n  i"
  },
  {
    "path": "config/samples/operator-utils_v1alpha1_templatedenforcingcrd.yaml",
    "chars": 810,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: TemplatedEnforcingCRD\nmetadata:\n  name: example-enforcingcrd\nspec:\n"
  },
  {
    "path": "config/scorecard/bases/config.yaml",
    "chars": 134,
    "preview": "apiVersion: scorecard.operatorframework.io/v1alpha3\nkind: Configuration\nmetadata:\n  name: config\nstages:\n- parallel: tru"
  },
  {
    "path": "config/scorecard/kustomization.yaml",
    "chars": 384,
    "preview": "resources:\n- bases/config.yaml\npatchesJson6902:\n- path: patches/basic.config.yaml\n  target:\n    group: scorecard.operato"
  },
  {
    "path": "config/scorecard/patches/basic.config.yaml",
    "chars": 230,
    "preview": "- op: add\n  path: /stages/0/tests/-\n  value:\n    entrypoint:\n    - scorecard-test\n    - basic-check-spec\n    image: quay"
  },
  {
    "path": "config/scorecard/patches/olm.config.yaml",
    "chars": 1200,
    "preview": "- op: add\n  path: /stages/0/tests/-\n  value:\n    entrypoint:\n    - scorecard-test\n    - olm-bundle-validation\n    image:"
  },
  {
    "path": "config/webhook/kustomization.yaml",
    "chars": 83,
    "preview": "resources:\n- manifests.yaml\n- service.yaml\n\nconfigurations:\n- kustomizeconfig.yaml\n"
  },
  {
    "path": "config/webhook/kustomizeconfig.yaml",
    "chars": 791,
    "preview": "# the following config is for teaching kustomize where to look at when substituting vars.\n# It requires kustomize v2.1.0"
  },
  {
    "path": "config/webhook/service.yaml",
    "chars": 189,
    "preview": "\napiVersion: v1\nkind: Service\nmetadata:\n  name: webhook-service\n  namespace: system\nspec:\n  ports:\n    - port: 443\n     "
  },
  {
    "path": "controllers/enforcingcrd_controller.go",
    "chars": 5204,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "controllers/enforcingpatch_controller.go",
    "chars": 3849,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "controllers/mycrd_controller.go",
    "chars": 4127,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "controllers/suite_test.go",
    "chars": 2034,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "controllers/templatedenforcingcrd_controller.go",
    "chars": 5397,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "go.mod",
    "chars": 4376,
    "preview": "module github.com/redhat-cop/operator-utils\n\ngo 1.21\n\nrequire (\n\tgithub.com/BurntSushi/toml v1.3.2\n\tgithub.com/Mastermin"
  },
  {
    "path": "go.sum",
    "chars": 35327,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "hack/boilerplate.go.txt",
    "chars": 531,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "main.go",
    "chars": 3939,
    "preview": "/*\n\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with"
  },
  {
    "path": "pkg/util/apis/conditions.go",
    "chars": 2130,
    "preview": "package apis\n\nimport (\n\t\"sort\"\n\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\nconst ReconcileError = \"ReconcileError"
  },
  {
    "path": "pkg/util/apis/key.go",
    "chars": 992,
    "preview": "package apis\n\nimport (\n\t\"errors\"\n\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tctr"
  },
  {
    "path": "pkg/util/crud/crudutils.go",
    "chars": 7603,
    "preview": "package crud\n\nimport (\n\t\"context\"\n\t\"text/template\"\n\n\t\"github.com/redhat-cop/operator-utils/pkg/util/templates\"\n\tapierror"
  },
  {
    "path": "pkg/util/discoveryclient/discoveryclientutils.go",
    "chars": 2737,
    "preview": "package discoveryclient\n\nimport (\n\t\"context\"\n\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tv1 \"k8s.io/apimachinery/p"
  },
  {
    "path": "pkg/util/dynamicclient/dynamicclientutils.go",
    "chars": 5147,
    "preview": "package dynamicclient\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachin"
  },
  {
    "path": "pkg/util/finalizer.go",
    "chars": 1531,
    "preview": "/*\nCopyright 2019 Red Hat, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/enforcing-reconciler.go",
    "chars": 13470,
    "preview": "package lockedresourcecontroller\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/go-logr/logr\"\n\t\"github.com/redhat-cop/operat"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/locked-resource-manager.go",
    "chars": 17189,
    "preview": "package lockedresourcecontroller\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\n\t\"github.com/go-logr/logr\"\n\tmultierror"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/lockedpatch/lockedpatch.go",
    "chars": 2735,
    "preview": "package lockedpatch\n\nimport (\n\t\"text/template\"\n\n\t\"github.com/go-logr/logr\"\n\tutilsapi \"github.com/redhat-cop/operator-uti"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/lockedresource/lockedresource.go",
    "chars": 5251,
    "preview": "package lockedresource\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"text/template\"\n\n\t\"github.com/go-logr/logr\"\n\tutilsapi \"git"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/lockedresource/lockedresourceset/lockedresourceset.go",
    "chars": 6828,
    "preview": "// Copyright (C) 2017 ScyllaDB\n// Use of this source code is governed by a ALv2-style\n// license that can be found at ht"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/lockedresource/lockedresourceset/lockedresourceset_bench_test.go",
    "chars": 3371,
    "preview": "// Copyright (C) 2017 ScyllaDB\n// Use of this source code is governed by a ALv2-style\n// license that can be found at ht"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/lockedresource/lockedresourceset/lockedresourceset_test.go",
    "chars": 14238,
    "preview": "// Copyright (C) 2017 ScyllaDB\n// Use of this source code is governed by a ALv2-style\n// license that can be found at ht"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/lockedresource/patch.go",
    "chars": 2461,
    "preview": "package lockedresource\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n\n\tjsonpatch \"github.com/evanphx/json-patch\"\n\t\"k8s.io/apimac"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/patch-reconciler.go",
    "chars": 21307,
    "preview": "package lockedresourcecontroller\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n"
  },
  {
    "path": "pkg/util/lockedresourcecontroller/resource-reconciler.go",
    "chars": 11580,
    "preview": "package lockedresourcecontroller\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"sync\"\n\n\t\"encoding/json\"\n\n\t\"github.com/go-logr/logr\"\n\n"
  },
  {
    "path": "pkg/util/owner.go",
    "chars": 1023,
    "preview": "/*\nCopyright 2019 Red Hat, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
  },
  {
    "path": "pkg/util/predicates.go",
    "chars": 1405,
    "preview": "/*\nCopyright 2019 Red Hat, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
  },
  {
    "path": "pkg/util/reconciler.go",
    "chars": 15749,
    "preview": "/*\nCopyright 2019 Red Hat, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
  },
  {
    "path": "pkg/util/stoppablemanager/stoppable-manager.go",
    "chars": 1675,
    "preview": "package stoppablemanager\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"k8s.io/client-go/rest\"\n\tlogf \"sigs.k8s.io/controller-runtime/"
  },
  {
    "path": "pkg/util/templates/advanced-funcmap.go",
    "chars": 7453,
    "preview": "/*\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with t"
  },
  {
    "path": "pkg/util/templates/templates.go",
    "chars": 4256,
    "preview": "/*\nCopyright 2019 Red Hat, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this fi"
  },
  {
    "path": "test/enforcing-patch-multiple-cluster-level.yaml",
    "chars": 585,
    "preview": "# test multiple instances cluster\napiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingPatch\nmetadata:\n  name: "
  },
  {
    "path": "test/enforcing-patch-multiple.yaml",
    "chars": 606,
    "preview": "#test multiple instances namespaced\napiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingPatch\nmetadata:\n  name"
  },
  {
    "path": "test/enforcing-patch.yaml",
    "chars": 736,
    "preview": "\n# # test single instance namespaced\napiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingPatch\nmetadata:\n  nam"
  },
  {
    "path": "test/enforcing_cr.yaml",
    "chars": 788,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingCRD\nmetadata:\n  name: example-enforcingcrd\nspec:\n  resourc"
  },
  {
    "path": "test/failing-enforcing_cr.yaml",
    "chars": 806,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: EnforcingCRD\nmetadata:\n  name: example-enforcingcrd2\nspec:\n  resour"
  },
  {
    "path": "test/mycrd_cr.yaml",
    "chars": 167,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: MyCRD\nmetadata:\n  name: example-mycrd\nspec:\n  # Add fields here\n  i"
  },
  {
    "path": "test/templatedenforcing_cr.yaml",
    "chars": 810,
    "preview": "apiVersion: operator-utils.example.io/v1alpha1\nkind: TemplatedEnforcingCRD\nmetadata:\n  name: example-enforcingcrd\nspec:\n"
  },
  {
    "path": "testbin/setup-envtest.sh",
    "chars": 2856,
    "preview": "#!/usr/bin/env bash\n\n#  Copyright 2020 The Kubernetes Authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the "
  }
]

About this extraction

This page contains the full source code of the redhat-cop/operator-utils GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 121 files (489.2 KB), approximately 163.9k tokens, and a symbol index with 342 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!