diff --git a/.github/workflows/build-and-push.yaml b/.github/workflows/build-and-push.yaml new file mode 100644 index 00000000..919430c8 --- /dev/null +++ b/.github/workflows/build-and-push.yaml @@ -0,0 +1,51 @@ +# This workflow will build the CodeFlare Operator image and push it to the opendatahub image registry + +name: Build and Push + +on: + pull_request: + types: + - closed + workflow_dispatch: + +jobs: + build-and-push: + if: (github.event.pull_request.merged == true && github.event.pull_request.user.login == 'codeflare-machine-account' && contains(github.event.pull_request.title, 'Sync with Upstream')) || github.event_name == 'workflow_dispatch' + name: Build and push ODH/CFO image + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set Go + uses: actions/setup-go@v3 + with: + go-version: v1.20 + + - name: Login to Quay.io + uses: redhat-actions/podman-login@v1 + with: + username: ${{ secrets.QUAY_BOT_USER }} + password: ${{ secrets.QUAY_BOT_PASSWORD }} + registry: quay.io + + - name: Get Upstream Release Tags + id: release-tags + run: | + release_tag=$(gh release view -R github.com/project-codeflare/codeflare-operator --json tagName | jq -r '.tagName') + echo "RELEASE_TAG=$release_tag" >> $GITHUB_ENV + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Cleanup the go.mod and go.sum + run: | + go mod tidy + + - name: Image Build and Push + run: | + make build + make image-build -e IMG=quay.io/opendatahub/codeflare-operator:${{ env.RELEASE_TAG }} + make image-push -e IMG=quay.io/opendatahub/codeflare-operator:${{ env.RELEASE_TAG }} + + - name: Delete remote branch + run: | + git push origin --delete sync-cfo-fork diff --git a/.github/workflows/component_tests.yaml b/.github/workflows/component_tests.yaml new file mode 100644 index 00000000..8f5bf7a6 --- /dev/null +++ b/.github/workflows/component_tests.yaml @@ -0,0 +1,43 @@ +name: Component tests + +on: + pull_request: + branches: + - main + - 'release-*' + paths-ignore: + - 'docs/**' + - '**.adoc' + - '**.md' + - 'LICENSE' + push: + branches: + - main + - 'release-*' + paths-ignore: + - 'docs/**' + - '**.adoc' + - '**.md' + - 'LICENSE' + +concurrency: + group: ${{ github.head_ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + kubernetes-component: + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' + + - name: Run component tests + run: | + make test-component diff --git a/.github/workflows/mnist-job-test-image.yml b/.github/workflows/mnist-job-test-image.yml new file mode 100644 index 00000000..02c4b5c7 --- /dev/null +++ b/.github/workflows/mnist-job-test-image.yml @@ -0,0 +1,36 @@ +# This workflow will build the MNIST job test image and push it to the project-codeflare image registry + +name: MNIST Job Test Image + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - 'test/pytorch_mnist_image/**' + +jobs: + push: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' + + - name: Login to Quay.io + id: podman-login-quay + run: | + podman login --username ${{ secrets.QUAY_ID }} --password ${{ secrets.QUAY_TOKEN }} quay.io + + - name: Image Build and Push + run: | + make image-mnist-job-test-push + + - name: Logout from Quay.io + if: always() && steps.podman-login-quay.outcome == 'success' + run: | + podman logout quay.io diff --git a/.github/workflows/odh-fork-sync.yml b/.github/workflows/odh-fork-sync.yml new file mode 100644 index 00000000..22f42f00 --- /dev/null +++ b/.github/workflows/odh-fork-sync.yml @@ -0,0 +1,18 @@ +name: Call sync on OpenDataHub CFO fork sync +on: + release: + types: + - published + workflow_dispatch: + +jobs: + sync-fork: + runs-on: ubuntu-latest + steps: + - name: Sync-fork + run: | + gh workflow run sync-fork.yaml --repo github.com/opendatahub-io/codeflare-operator --ref main + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: + bash diff --git a/.github/workflows/odh-release.yml b/.github/workflows/odh-release.yml new file mode 100644 index 00000000..900e910b --- /dev/null +++ b/.github/workflows/odh-release.yml @@ -0,0 +1,49 @@ +# This workflow will compile e2e tests and release them + +name: ODH Release +on: + workflow_dispatch: + inputs: + version: + description: 'Tag to be used for release, i.e.: v0.0.1' + required: true + +jobs: + release-odh: + runs-on: ubuntu-latest + + # Permission required to create a release + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version: v1.20 + + - name: Verify that release doesn't exist yet + shell: bash {0} + run: | + gh release view ${{ github.event.inputs.version }} + status=$? + if [[ $status -eq 0 ]]; then + echo "Release ${{ github.event.inputs.version }} already exists." + exit 1 + fi + env: + GITHUB_TOKEN: ${{ github.TOKEN }} + + - name: Compile tests + run: | + go test -c -o compiled-tests/e2e ./test/e2e/ + go test -c -o compiled-tests/odh ./test/odh/ + + - name: Creates a release in GitHub + run: | + gh release create ${{ github.event.inputs.version }} --target ${{ github.ref }} compiled-tests/* + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: bash diff --git a/.github/workflows/operator-image.yml b/.github/workflows/operator-image.yml index 54c6403a..0713d36c 100644 --- a/.github/workflows/operator-image.yml +++ b/.github/workflows/operator-image.yml @@ -1,48 +1,41 @@ -# This workflow will build the CodeFlare Operator image and push it to the project-codeflare image registry +# This workflow will build the CodeFlare Operator dev image and push it to the project-codeflare image registry -name: Operator Image +name: Operator Dev Image on: - workflow_dispatch: - inputs: - tag: - description: 'Tag to be used for operator image' - required: true - default: 'unstable' + push: + branches: + - main + paths-ignore: + - 'docs/**' + - 'test/**' + - '**.adoc' + - '**.md' + - 'LICENSE' jobs: push: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Install operator-sdk - run: | - export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac) - export OS=$(uname | awk '{print tolower($0)}') - export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.27.0 - curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH} - chmod +x operator-sdk_${OS}_${ARCH} && sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' - name: Login to Quay.io - uses: redhat-actions/podman-login@v1 - with: - username: ${{ secrets.QUAY_ID }} - password: ${{ secrets.QUAY_TOKEN }} - registry: quay.io + id: podman-login-quay + run: | + podman login --username ${{ secrets.QUAY_ID }} --password ${{ secrets.QUAY_TOKEN }} quay.io - name: Image Build run: | make build - make bundle - make image-build -e IMG=quay.io/project-codeflare/codeflare-operator:${SOURCE_TAG} - podman tag quay.io/project-codeflare/codeflare-operator:${SOURCE_TAG} quay.io/project-codeflare/codeflare-operator:latest - env: - SOURCE_TAG: ${{ github.event.inputs.tag }} + make image-build -e IMG=quay.io/project-codeflare/codeflare-operator:dev + make image-push -e IMG=quay.io/project-codeflare/codeflare-operator:dev - - name: Image Push + - name: Logout from Quay.io + if: always() && steps.podman-login-quay.outcome == 'success' run: | - make image-push -e IMG=quay.io/project-codeflare/codeflare-operator:${SOURCE_TAG} - make image-push -e IMG=quay.io/project-codeflare/codeflare-operator:latest - env: - SOURCE_TAG: ${{ github.event.inputs.tag }} + podman logout quay.io diff --git a/.github/workflows/precommit.yml b/.github/workflows/precommit.yml index 494e0dd3..267d537a 100644 --- a/.github/workflows/precommit.yml +++ b/.github/workflows/precommit.yml @@ -21,10 +21,15 @@ jobs: volumes: - /cache steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' - name: Activate cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /cache key: ${{ runner.os }}-cache-${{ hashFiles('**/go.sum', '.pre-commit-config.yaml') }} diff --git a/.github/workflows/project-codeflare-release.yml b/.github/workflows/project-codeflare-release.yml new file mode 100644 index 00000000..017c7b02 --- /dev/null +++ b/.github/workflows/project-codeflare-release.yml @@ -0,0 +1,120 @@ +# This workflow will build and release all components of the CodeFlare project + +name: Project CodeFlare Release +on: + workflow_dispatch: + inputs: + operator-version: + description: 'CodeFlare operator version to be released (for example: v0.0.0)' + required: true + replaces: + description: 'The previous operator semantic version that this release replaces (for example: v0.0.0)' + required: true + codeflare-sdk-version: + description: 'Version of CodeFlare-SDK to be released (for example: v0.0.0)' + required: true + kuberay-version: + description: 'Tested version of KubeRay (for example: v0.0.0)' + required: true + is-stable: + description: 'Select if the built images should be tagged as stable' + required: true + type: boolean + codeflare-repository-organization: + description: 'GitHub organization/user containing repositories used for release' + required: true + default: 'project-codeflare' + quay-organization: + description: 'Quay organization used to push the built images to' + required: true + default: 'project-codeflare' + community-operators-prod-organization: + description: 'Owner of target community-operators-prod repository used to open a PR against' + required: true + default: 'redhat-openshift-ecosystem' + +jobs: + release-parameters: + runs-on: ubuntu-latest + steps: + - name: Release Parameters + run: | + echo "Below are the release parameters set for the workflow:" + echo "Operator Version: ${{ github.event.inputs.operator-version }}" + echo "Replaces: ${{ github.event.inputs.replaces }}" + echo "CodeFlare SDK Version: ${{ github.event.inputs.codeflare-sdk-version }}" + echo "Tested KubeRay Version: ${{ github.event.inputs.kuberay-version }}" + echo "Is Stable: ${{ github.event.inputs.is-stable }}" + echo "CodeFlare Repository Organization: ${{ github.event.inputs.codeflare-repository-organization }}" + echo "Quay Organization: ${{ github.event.inputs.quay-organization }}" + echo "Community Operators Prod Organization: ${{ github.event.inputs.community-operators-prod-organization }}" + + release-codeflare-sdk: + needs: check-kuberay-version + runs-on: ubuntu-latest + + steps: + - name: Check if Codeflare SDK release does exist + run: | + status_code=$(curl -s -o /dev/null -w "%{http_code}" https://github.com/project-codeflare/codeflare-sdk/releases/tag/${{ github.event.inputs.codeflare-sdk-version }}) + if [[ "$status_code" == "200" ]]; then + echo "SDK release with version ${{ github.event.inputs.codeflare-sdk-version }} already exist. Will not create SDK release." + fi + echo "SDK_RELEASE_STATUS_CODE=$status_code" >> $GITHUB_ENV + + - name: Release CodeFlare SDK + run: | + semver_version="${{ github.event.inputs.codeflare-sdk-version }}" + plain_version="${semver_version:1}" + gh workflow run release.yaml --repo ${{ github.event.inputs.codeflare-repository-organization }}/codeflare-sdk --ref ${{ github.ref }} --field release-version=${plain_version} --field is-stable=${{ github.event.inputs.is-stable }} --field quay-organization=${{ github.event.inputs.quay-organization }} + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: bash + if: ${{ env.SDK_RELEASE_STATUS_CODE != '200' }} + + - name: Wait for CodeFlare SDK run to finish + run: | + # wait for a while for Run to be started + sleep 5 + run_id=$(gh run list --workflow release.yaml --repo ${{ github.event.inputs.codeflare-repository-organization }}/codeflare-sdk --limit 1 --json databaseId --jq .[].databaseId) + gh run watch ${run_id} --repo ${{ github.event.inputs.codeflare-repository-organization }}/codeflare-sdk --interval 10 --exit-status + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: bash + if: ${{ env.SDK_RELEASE_STATUS_CODE != '200' }} + + release-codeflare-operator: + needs: [release-codeflare-sdk] + runs-on: ubuntu-latest + + steps: + - name: Release CodeFlare operator + run: | + gh workflow run tag-and-build.yml --repo ${{ github.event.inputs.codeflare-repository-organization }}/codeflare-operator --ref ${{ github.ref }} --field is-stable=${{ github.event.inputs.is-stable }} --field version=${{ github.event.inputs.operator-version }} --field replaces=${{ github.event.inputs.replaces }} --field codeflare-sdk-version=${{ github.event.inputs.codeflare-sdk-version }} --field kuberay-version=${{ github.event.inputs.kuberay-version }} --field quay-organization=${{ github.event.inputs.quay-organization }} --field community-operators-prod-fork-organization=${{ github.event.inputs.codeflare-repository-organization }} --field community-operators-prod-organization=${{ github.event.inputs.community-operators-prod-organization }} + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: bash + + - name: Wait for CodeFlare operator run to finish + run: | + # wait for a while for Run to be started + sleep 5 + run_id=$(gh run list --workflow tag-and-build.yml --repo ${{ github.event.inputs.codeflare-repository-organization }}/codeflare-operator --limit 1 --json databaseId --jq .[].databaseId) + gh run watch ${run_id} --repo ${{ github.event.inputs.codeflare-repository-organization }}/codeflare-operator --interval 10 --exit-status + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: bash + + check-kuberay-version: + runs-on: ubuntu-latest + + steps: + - name: Check if KubeRay release exists + run: | + status_code=$(curl -s -o /dev/null -w "%{http_code}" https://github.com/ray-project/kuberay/releases/tag/${{ github.event.inputs.kuberay-version }}) + if [[ "$status_code" == "200" ]]; then + echo "KubeRay release with version ${{ github.event.inputs.kuberay-version }} exists and available to use." + else + echo "KubeRay release with version ${{ github.event.inputs.kuberay-version }} does not exist. Please select an existing version." + exit 1 + fi diff --git a/.github/workflows/sync-fork.yaml b/.github/workflows/sync-fork.yaml new file mode 100644 index 00000000..0c162a3a --- /dev/null +++ b/.github/workflows/sync-fork.yaml @@ -0,0 +1,39 @@ +# This workflow will create a sync pr for the opendatahub-io/codeflare-operator fork with project-codeflare/codeflare-operator + +name: Create Sync Fork PR + +on: + workflow_dispatch: + +jobs: + create-fork-sync-pr: + runs-on: ubuntu-latest + + env: + GIT_BRANCH: ${GITHUB_REF#refs/heads/} + + steps: + - uses: actions/checkout@v3 + with: + persist-credentials: false + - name: repo-sync + uses: repo-sync/github-sync@v2 + with: + source_repo: "https://github.com/project-codeflare/codeflare-operator.git" + source_branch: ${{ env.GIT_BRANCH }} + destination_branch: "sync-cfo-fork" + github_token: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + + - name: Set up Git + run: | + git config --global user.email "138894154+codeflare-machine-account@users.noreply.github.com" + git config --global user.name "codeflare-machine-account" + + - name: Create Pull Request + run: | + PR_TITLE="Sync with Upstream" + PR_BODY="This pull request updates the fork to match the latest changes from the upstream repository." + gh pr create --base "${{ env.GIT_BRANCH }}" --head sync-cfo-fork --title "$PR_TITLE" --body "$PR_BODY" + env: + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + shell: bash diff --git a/.github/workflows/tag-and-build.yml b/.github/workflows/tag-and-build.yml index 413ccf2d..dc4a07a2 100644 --- a/.github/workflows/tag-and-build.yml +++ b/.github/workflows/tag-and-build.yml @@ -12,16 +12,12 @@ on: description: 'The previous semantic version that this tag replaces.' required: true default: 'v0.0.0-dev' - mcad-version: - description: 'Published version of multi-cluster-app-dispatcher' - required: true - default: 'v0.0.0-dev' codeflare-sdk-version: description: 'Published version of CodeFlare-SDK' required: true default: 'v0.0.0-dev' - instascale-version: - description: 'Published version of InstaScale' + kuberay-version: + description: 'Tested version of KubeRay' required: true default: 'v0.0.0-dev' is-stable: @@ -48,9 +44,19 @@ jobs: # Permission required to create a release permissions: contents: write + pull-requests: write + + env: + IMAGE_ORG_BASE: quay.io/${{ github.event.inputs.quay-organization }} + PR_BRANCH_NAME: adjustments-release-${{ github.event.inputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' - name: Verify that release doesn't exist yet shell: bash {0} @@ -65,7 +71,7 @@ jobs: GITHUB_TOKEN: ${{ github.TOKEN }} - name: Activate cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /cache key: ${{ runner.os }}-cache-${{ hashFiles('**/go.sum', '.pre-commit-config.yaml') }} @@ -73,12 +79,29 @@ jobs: - name: Install operator-sdk run: make install-operator-sdk + - name: Adjust Compatibility Matrix in readme + run: | + sed -i -E "s|(.*CodeFlare Operator.*\[).*(\].*releases/tag/).*(\).*)|\1${{ github.event.inputs.version }}\2${{ github.event.inputs.version }}\3|" README.md + sed -i -E "s|(.*CodeFlare-SDK.*\[).*(\].*releases/tag/).*(\).*)|\1${{ github.event.inputs.codeflare-sdk-version }}\2${{ github.event.inputs.codeflare-sdk-version }}\3|" README.md + sed -i -E "s|(.*KubeRay.*\[).*(\].*releases/tag/).*(\).*)|\1${{ github.event.inputs.kuberay-version }}\2${{ github.event.inputs.kuberay-version }}\3|" README.md + + - name: Adjust Kuberay dependency in the code + run: | + sed -i -E "s/(.*KUBERAY_VERSION \?= ).*/\1${{ github.event.inputs.kuberay-version }}/" Makefile + + - name: Update image version in params.env + run: | + VERSION=${{ github.event.inputs.version }} perl -i -pe 's/:(.*)$/:$ENV{"VERSION"}/' config/manager/params.env + shell: bash + - name: Login to Quay.io - uses: redhat-actions/podman-login@v1 - with: - username: ${{ secrets.QUAY_ID }} - password: ${{ secrets.QUAY_TOKEN }} - registry: quay.io + id: podman-login-quay + run: | + podman login --username ${{ secrets.QUAY_ID }} --password ${{ secrets.QUAY_TOKEN }} quay.io + + - name: Align go.mod and go.sum dependencies for released components + run: | + make modules - name: Image Build and Push run: | @@ -92,40 +115,48 @@ jobs: podman tag quay.io/${{ github.event.inputs.quay-organization }}/codeflare-operator:${{ github.event.inputs.version }} quay.io/${{ github.event.inputs.quay-organization }}/codeflare-operator:stable make image-push -e IMG=quay.io/${{ github.event.inputs.quay-organization }}/codeflare-operator:stable - - name: Build bundle and create PR in OpenShift community operators repository + - name: Cleanup the go.mod and go.sum run: | - git config --global user.email "codeflare-ci@redhat.com" - git config --global user.name "CodeFlare CI" - make openshift-community-operator-release + go mod tidy + + - name: Regenerate CFO CRD manifests + run: | + make manifests + + - name: Commit changes in the code back to repository + id: create-pr-branch + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Update dependency versions for release ${{ github.event.inputs.version }} + file_pattern: 'README.md *.yaml Makefile go.mod go.sum *.env' + create_branch: true + branch: ${{ env.PR_BRANCH_NAME }} + + - name: Create a PR with code changes + run: | + GIT_BRANCH=${GITHUB_REF#refs/heads/} + gh pr create --base "$GIT_BRANCH" --fill --head "${{ env.PR_BRANCH_NAME }}" --label "lgtm" --label "approved" env: - VERSION: ${{ github.event.inputs.version }} - PREVIOUS_VERSION: ${{ github.event.inputs.replaces }} - INSTASCALE_VERSION: ${{ github.event.inputs.instascale-version }} - MCAD_VERSION: ${{ github.event.inputs.mcad-version }} - GH_TOKEN: ${{ secrets.GH_PAT }} - IMAGE_ORG_BASE: quay.io/${{ github.event.inputs.quay-organization }} - OPERATORS_REPO_FORK_ORG: ${{ github.event.inputs.community-operators-prod-fork-organization }} - OPERATORS_REPO_ORG: ${{ github.event.inputs.community-operators-prod-organization }} + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} - - name: Adjust Compatibility Matrix in readme + - name: Wait until PR with code changes is merged + id: wait-pr-merge run: | - sed -i -E "s/(.*CodeFlare Operator.*)v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.version }}\2/" README.md - sed -i -E "s/(.*Multi-Cluster App Dispatcher.*)v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.mcad-version }}\2/" README.md - sed -i -E "s/(.*CodeFlare-SDK.*)v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.codeflare-sdk-version }}\2/" README.md - sed -i -E "s/(.*InstaScale.*)v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.instascale-version }}\2/" README.md + timeout 3600 bash -c 'until [[ $(gh pr view '${{ env.PR_BRANCH_NAME }}' --json state --jq .state) == "MERGED" ]]; do sleep 5 && echo "$(gh pr view '${{ env.PR_BRANCH_NAME }}' --json state --jq .state)"; done' + env: + GITHUB_TOKEN: ${{ github.TOKEN }} - - name: Adjust MCAD and InstaScale dependencies in the code + - name: Close PR if PR merge failed + if: always() && (steps.wait-pr-merge.outcome == 'failure' || steps.wait-pr-merge.outcome == 'cancelled') run: | - sed -i -E "s/(.*MCAD_VERSION \?= )v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.mcad-version }}\2/" Makefile - sed -i -E "s/(.*INSTASCALE_VERSION \?= )v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.instascale-version }}\2/" Makefile - sed -i -E "s/(.*instascale-controller:)v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.instascale-version }}\2/" controllers/testdata/instascale_test_results/case_1/deployment.yaml - sed -i -E "s/(.*instascale-controller:)v[0-9]+\.[0-9]+\.[0-9]+(.*)/\1${{ github.event.inputs.instascale-version }}\2/" controllers/testdata/instascale_test_results/case_2/deployment.yaml + gh pr close ${{ env.PR_BRANCH_NAME }} + env: + GITHUB_TOKEN: ${{ github.TOKEN }} - - name: Commit readme changes back to repository - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: Update dependency versions for release ${{ github.event.inputs.version }} - file_pattern: 'README.md controllers/defaults.go *.yaml *.tmpl Makefile' + - name: Delete remote branch + if: always() && steps.create-pr-branch.outcome == 'success' + run: | + git push origin --delete ${{ env.PR_BRANCH_NAME }} - name: Creates a release in GitHub run: | @@ -137,5 +168,22 @@ jobs: gh release edit ${{ github.event.inputs.version }} --notes-file release-notes.md rm release-notes.md env: - GITHUB_TOKEN: ${{ github.TOKEN }} + GITHUB_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} shell: bash + + - name: Build bundle and create PR in OpenShift community operators repository + run: | + git config --global user.email "138894154+codeflare-machine-account@users.noreply.github.com" + git config --global user.name "codeflare-machine-account" + make openshift-community-operator-release + env: + VERSION: ${{ github.event.inputs.version }} + PREVIOUS_VERSION: ${{ github.event.inputs.replaces }} + GH_TOKEN: ${{ secrets.CODEFLARE_MACHINE_ACCOUNT_TOKEN }} + OPERATORS_REPO_FORK_ORG: ${{ github.event.inputs.community-operators-prod-fork-organization }} + OPERATORS_REPO_ORG: ${{ github.event.inputs.community-operators-prod-organization }} + + - name: Logout from Quay.io + if: always() && steps.podman-login-quay.outcome == 'success' + run: | + podman logout quay.io diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index f28c5b2b..b8e39f08 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -22,10 +22,15 @@ jobs: volumes: - /cache steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' - name: Activate cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /cache key: ${{ runner.os }}-cache-${{ hashFiles('**/go.sum', '.pre-commit-config.yaml') }} diff --git a/.github/workflows/verify_generated_files.yml b/.github/workflows/verify_generated_files.yml new file mode 100644 index 00000000..a5f6eb38 --- /dev/null +++ b/.github/workflows/verify_generated_files.yml @@ -0,0 +1,40 @@ +name: Verify Generated Files and Import Organization +on: + push: + branches: + - '**' + paths: + - '**.go' + - '**go.mod' + - '**go.sum' + - 'config/**' + tags-ignore: + - 'v*' + pull_request: + paths: + - '**.go' + - '**go.mod' + - '**go.sum' + - 'config/**' +jobs: + verify-imports: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' + - name: Verify that imports are organized + run: make verify-imports + + verify-manifests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set Go + uses: actions/setup-go@v5 + with: + go-version-file: './go.mod' + - name: Verify that the latest WebhookConfigurations, ClusterRoles, and CustomResourceDefinitions have been generated + run: make manifests && git diff --exit-code diff --git a/.gitignore b/.gitignore index 898d0779..9be9b01b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ bundle.Dockerfile *~ .DS_STORE + +# VSCode +.vscode diff --git a/.golangci.yaml b/.golangci.yaml index e4fc63b6..e2afb25b 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,5 +1,5 @@ run: - timeout: 5m + timeout: 10m linters: enable: - errcheck @@ -9,4 +9,3 @@ linters: - staticcheck - typecheck - unused - - revive diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba68a441..985aeaa7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,5 +25,4 @@ repos: hooks: - id: go-fmt - id: golangci-lint - - id: go-build - id: go-mod-tidy diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..731487da --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug CodeFlare Operator", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/main.go", + "env": { + "KUBECONFIG": "", + "NAMESPACE": "" + }, + "showLog": true + } + ] +} diff --git a/.yamllint.yaml b/.yamllint.yaml index 75b22773..768bc626 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -1,5 +1,5 @@ ignore: | - bundle/manifests/mcad.ibm.com* + bundle/manifests/* extends: default rules: line-length: disable diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f321c10d..3d7bf8d3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ Here are a few things to go over before getting started with CodeFlare Operator ## Environment setup The following should be installed in your working environment: - - Go 1.18.X + - Go 1.20.x - [Download release](https://go.dev/dl/) - [Install Instructions](https://go.dev/doc/install) - [Operator SDK](https://sdk.operatorframework.io/docs/installation/) @@ -14,15 +14,6 @@ The following should be installed in your working environment: ## Basic Overview The main entrypoint for the operator is `main.go` -The MCAD and InstaScale custom resources are defined under the `api` dir: - - See `mcad_types.go` and `instascale_types.go` - -The MCAD and InstaScale resource templates can be found under `config/internal`: - - Sorted under `mcad` and `insascale` subdirs - -The code for MCAD/InstaScale resource reconcilliation can be found in the `controllers` dir: - - See `mcad_controller.go` and `instascale_controller.go` - ## Building and Deployment If changes are made in the `api` dir, run: `make manifests` - This will generate new CRDs and associated files @@ -53,6 +44,12 @@ The CodeFlare Operator currently has unit tests and pre-commit checks - Note that both are required for CI to pass on pull requests To write and inspect unit tests: - - MCAD and InstaScale unit tests under `mcad_controller_test.go` and `instascale_controller_test.go` in the `controllers` dir - Unit test functions are defined in `suite_test.go` (with utils in `util/util.go`) in the `controllers dir` - Test cases defined under `controllers/testdata` + + ## Local debugging with VSCode + Steps outlining how to run the operator locally. + - Ensure you are authenticated to your Kubernetes/OpenShift Cluster. + - Populate the [.vscode/launch.json](https://github.com/project-codeflare/codeflare-operator/tree/main/.vscode/launch.json) file with the location of your Kubernetes config file and desired namespace. + - In VSCode on the activity bar click `Run and Debug` or `CTRL + SHIFT + D` to start a local debugging session of the CodeFlare Operator. + The operator should be running as intended. diff --git a/Dockerfile b/Dockerfile index b9717367..f5c51c3f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM registry.access.redhat.com/ubi8/go-toolset:1.18.9-8 as builder +FROM registry.access.redhat.com/ubi8/go-toolset:1.20.10 as builder WORKDIR /workspace # Copy the Go Modules manifests @@ -7,19 +7,17 @@ COPY go.mod go.mod COPY go.sum go.sum RUN go mod download -# Copy the go source +# Copy the Go sources COPY main.go main.go -COPY api/ api/ -COPY controllers/ controllers/ +COPY pkg/ pkg/ # Build USER root -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go +RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -tags strictfipsruntime -a -o manager main.go -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7 +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8 WORKDIR / COPY --from=builder /workspace/manager . -COPY config/internal config/internal USER 65532:65532 ENTRYPOINT ["/manager"] diff --git a/Makefile b/Makefile index a6a5c1f1..61b524b7 100644 --- a/Makefile +++ b/Makefile @@ -11,15 +11,11 @@ PREVIOUS_VERSION ?= v0.0.0-dev VERSION ?= v0.0.0-dev BUNDLE_VERSION ?= $(VERSION:v%=%) -# INSTASCALE_VERSION defines the default version of the InstaScale controller -INSTASCALE_VERSION ?= v0.0.4 +# KUBERAY_VERSION defines the default version of the KubeRay operator (used for testing) +KUBERAY_VERSION ?= v1.1.0 -# MCAD_VERSION defines the default version of the MCAD controller -MCAD_VERSION ?= v1.31.0 -# MCAD_REF, MCAD_REPO and MCAD_CRD define the reference to MCAD CRD resources -MCAD_REF ?= release-${MCAD_VERSION} -MCAD_REPO ?= github.com/project-codeflare/multi-cluster-app-dispatcher -MCAD_CRD ?= ${MCAD_REPO}/config/crd?ref=${MCAD_REF} +# RAY_VERSION defines the default version of Ray (used for testing) +RAY_VERSION ?= 2.5.0 # OPERATORS_REPO_ORG points to GitHub repository organization where bundle PR is opened against # OPERATORS_REPO_FORK_ORG points to GitHub repository fork organization where bundle build is pushed to @@ -55,12 +51,6 @@ IMAGE_ORG_BASE ?= quay.io/project-codeflare # codeflare.dev/codeflare-operator-bundle:$VERSION and codeflare.dev/codeflare-operator-catalog:$VERSION. IMAGE_TAG_BASE ?= $(IMAGE_ORG_BASE)/codeflare-operator -# MCAD_IMAGE defines the default container image for the MCAD controller -MCAD_IMAGE ?= $(IMAGE_ORG_BASE)/mcad-controller:$(MCAD_REF) - -# INSTASCALE_IMAGE defines the default container image for the InstaScale controller -INSTASCALE_IMAGE ?= $(IMAGE_ORG_BASE)/instascale-controller:$(INSTASCALE_VERSION) - # BUNDLE_IMG defines the image:tag used for the bundle. # You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:$(VERSION) @@ -81,6 +71,14 @@ IMG ?= ${IMAGE_TAG_BASE}:${VERSION} # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.24.2 +# The target deployment environment, that corresponds to the Kustomize directory +# used to build the manifests. +ENV ?= default + +# Image URL to build MNIST job test image +MNIST_JOB_TEST_VERSION ?= v0.0.2 +MNIST_JOB_TEST_IMG ?= $(IMAGE_ORG_BASE)/mnist-job-test:${MNIST_JOB_TEST_VERSION} + # 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 @@ -93,6 +91,18 @@ endif SHELL = /usr/bin/env bash -o pipefail .SHELLFLAGS = -ec +BUILD_DATE := $(shell date +%Y-%m-%d\ %H:%M) +BUILD_TAG_SHA := $(shell git rev-list --abbrev-commit --tags --max-count=1) +BUILD_TAG_NAME := $(shell git describe --abbrev=0 --tags ${BUILD_TAG_SHA} 2>/dev/null || true) +BUILD_SHA := $(shell git rev-parse --short HEAD) +BUILD_VERSION := $(BUILD_TAG_NAME:v%=%) +ifneq ($(BUILD_SHA), $(BUILD_TAG_SHA)) + BUILD_VERSION := $(BUILD_VERSION)-$(BUILD_SHA) +endif +ifneq ($(shell git status --porcelain),) + BUILD_VERSION := $(BUILD_VERSION)-dirty +endif + .PHONY: all all: build @@ -115,65 +125,10 @@ help: ## Display this help. ##@ Development -DEFAULTS_FILE := controllers/defaults.go - -.PHONY: defaults -defaults: - $(info Regenerating $(DEFAULTS_FILE)) - @echo "package controllers" > $(DEFAULTS_FILE) - @echo "" >> $(DEFAULTS_FILE) - @echo "// ***********************" >> $(DEFAULTS_FILE) - @echo "// DO NOT EDIT THIS FILE" >> $(DEFAULTS_FILE) - @echo "// ***********************" >> $(DEFAULTS_FILE) - @echo "" >> $(DEFAULTS_FILE) - @echo "const (" >> $(DEFAULTS_FILE) - @echo " MCADImage = \"$(MCAD_IMAGE)\"" >> $(DEFAULTS_FILE) - @echo " InstaScaleImage = \"$(INSTASCALE_IMAGE)\"" >> $(DEFAULTS_FILE) - @echo "" >> $(DEFAULTS_FILE) - @echo ")" >> $(DEFAULTS_FILE) - @echo "" >> $(DEFAULTS_FILE) - - gofmt -w $(DEFAULTS_FILE) - +# this encounters sed issues on MacOS, quick fix is to use gsed or to escape the parentheses i.e. \( \) .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: generate-client ## Generate client packages -generate-client: code-generator - rm -rf client - $(APPLYCONFIGURATION_GEN) \ - --input-dirs="github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" \ - --go-header-file="hack/boilerplate.go.txt" \ - --output-package="github.com/project-codeflare/codeflare-operator/client/applyconfiguration" \ - --trim-path-prefix "github.com/project-codeflare/codeflare-operator" - $(CLIENT_GEN) \ - --input="codeflare/v1alpha1" \ - --input-base="github.com/project-codeflare/codeflare-operator/api" \ - --apply-configuration-package="github.com/project-codeflare/codeflare-operator/client/applyconfiguration" \ - --go-header-file="hack/boilerplate.go.txt" \ - --clientset-name "versioned" \ - --output-package="github.com/project-codeflare/codeflare-operator/client/clientset" \ - --output-base="." \ - --trim-path-prefix "github.com/project-codeflare/codeflare-operator" - $(LISTER_GEN) \ - --input-dirs="github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" \ - --go-header-file="hack/boilerplate.go.txt" \ - --output-base="." \ - --output-package="github.com/project-codeflare/codeflare-operator/client/listers" \ - --trim-path-prefix "github.com/project-codeflare/codeflare-operator" - $(INFORMER_GEN) \ - --input-dirs="github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" \ - --versioned-clientset-package="github.com/project-codeflare/codeflare-operator/client/clientset/versioned" \ - --listers-package="github.com/project-codeflare/codeflare-operator/client/listers" \ - --go-header-file="hack/boilerplate.go.txt" \ - --output-base="." \ - --output-package="github.com/project-codeflare/codeflare-operator/client/informer" \ - --trim-path-prefix "github.com/project-codeflare/codeflare-operator" +manifests: controller-gen kustomize install-yq ## Generate RBAC objects. + $(CONTROLLER_GEN) rbac:roleName=manager-role webhook paths="./..." .PHONY: fmt fmt: ## Run go fmt against code. @@ -186,12 +141,22 @@ vet: ## Run go vet against code. ##@ Build +.PHONY: modules +modules: ## Update Go dependencies. + go get github.com/ray-project/kuberay/ray-operator@$(KUBERAY_VERSION) + go mod tidy + .PHONY: build -build: defaults generate fmt vet ## Build manager binary. - go build -o bin/manager main.go +build: fmt vet ## Build manager binary. + go build \ + -ldflags " \ + -X 'main.OperatorVersion=$(BUILD_VERSION)' \ + -X 'main.BuildDate=$(BUILD_DATE)' \ + " \ + -o bin/manager main.go .PHONY: run -run: defaults manifests generate fmt vet ## Run a controller from your host. +run: manifests fmt vet ## Run a controller from your host. go run ./main.go .PHONY: image-build @@ -199,7 +164,7 @@ image-build: test-unit ## Build container image with the manager. podman build -t ${IMG} . .PHONY: image-push -image-push: ## Push container image with the manager. +image-push: image-build ## Push container image with the manager. podman push ${IMG} ##@ Deployment @@ -211,21 +176,28 @@ endif .PHONY: install install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl apply -f - + git restore config/* .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 - + git restore config/* .PHONY: deploy deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) fn run config/crd/mcad --image gcr.io/kpt-fn/apply-setters:v0.2.0 -- MCAD_CRD=$(MCAD_CRD) - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default | kubectl apply -f - + cd config/manager && IMAGE=$(IMG) perl -i -pe 's/codeflare-operator-controller-image=(.*)$$/codeflare-operator-controller-image=$$ENV{"IMAGE"}/' params.env + $(KUSTOMIZE) build config/${ENV} | kubectl apply -f - git restore config/* .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 - + $(KUSTOMIZE) build config/${ENV} | kubectl delete --ignore-not-found=$(ignore-not-found) -f - + git restore config/* + +.PHONY: install-odh-operator +install-odh-operator: kustomize ## Install ODH operator into the OpenShift cluster specified in ~/.kube/config. + $(KUSTOMIZE) build config/odh-operator | kubectl apply -f - + kubectl wait -n openshift-operators subscription/opendatahub-operator --for=jsonpath='{.status.state}'=AtLatestKnown --timeout=180s ##@ Build Dependencies @@ -236,19 +208,20 @@ $(LOCALBIN): ## Tool Binaries KUSTOMIZE ?= $(LOCALBIN)/kustomize -APPLYCONFIGURATION_GEN ?= $(LOCALBIN)/applyconfiguration-gen -CLIENT_GEN ?= $(LOCALBIN)/client-gen -LISTER_GEN ?= $(LOCALBIN)/lister-gen -INFORMER_GEN ?= $(LOCALBIN)/informer-gen +YQ ?= $(LOCALBIN)/yq CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +GINKGO ?= $(LOCALBIN)/ginkgo ENVTEST ?= $(LOCALBIN)/setup-envtest +OPENSHIFT-GOIMPORTS ?= $(LOCALBIN)/openshift-goimports OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk GH_CLI ?= $(LOCALBIN)/gh +SED ?= /usr/bin/sed ## Tool Versions KUSTOMIZE_VERSION ?= v4.5.4 CODEGEN_VERSION ?= v0.27.2 CONTROLLER_TOOLS_VERSION ?= v0.9.2 +YQ_VERSION ?= v4.35.2 ## latest version that works with go1.20 OPERATOR_SDK_VERSION ?= v1.27.0 GH_CLI_VERSION ?= 2.30.0 @@ -269,44 +242,36 @@ $(GH_CLI): $(LOCALBIN) rm -rf $(GH_CLI_DL_FILENAME) rm $(GH_CLI_DL_FILENAME).tar.gz -.PHONY: code-generator -code-generator: $(APPLYCONFIGURATION_GEN) $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN) - -.PHONY: applyconfiguration-gen -applyconfiguration-gen: $(APPLYCONFIGURATION_GEN) -$(APPLYCONFIGURATION_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/applyconfiguration-gen || GOBIN=$(LOCALBIN) go install k8s.io/code-generator/cmd/applyconfiguration-gen@$(CODEGEN_VERSION) - -.PHONY: client-gen -client-gen: $(CLIENT_GEN) -$(CLIENT_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/client-gen || GOBIN=$(LOCALBIN) go install k8s.io/code-generator/cmd/client-gen@$(CODEGEN_VERSION) - -.PHONY: lister-gen -lister-gen: $(LISTER_GEN) -$(LISTER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/lister-gen || GOBIN=$(LOCALBIN) go install k8s.io/code-generator/cmd/lister-gen@$(CODEGEN_VERSION) - -.PHONY: informer-gen -informer-gen: $(INFORMER_GEN) -$(INFORMER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/informer-gen || GOBIN=$(LOCALBIN) go install k8s.io/code-generator/cmd/informer-gen@$(CODEGEN_VERSION) - .PHONY: controller-gen controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. $(CONTROLLER_GEN): $(LOCALBIN) test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) +.PHONY: ginkgo +ginkgo: $(GINKGO) ## Download ginkgo locally if necessary. +$(GINKGO): $(LOCALBIN) + test -s $(LOCALBIN)/ginkgo || GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo + +.PHONY: install-yq +install-yq: $(YQ) ## Download yq locally if necessary +$(YQ): $(LOCALBIN) + test -s $(LOCALBIN)/yq || GOBIN=$(LOCALBIN) go install github.com/mikefarah/yq/v4@$(YQ_VERSION) + .PHONY: envtest envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. $(ENVTEST): $(LOCALBIN) - test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@release-0.17 + +.PHONY: openshift-goimports +openshift-goimports: $(OPENSHIFT-GOIMPORTS) ## Download openshift-goimports locally if necessary. +$(OPENSHIFT-GOIMPORTS): $(LOCALBIN) + test -s $(LOCALBIN)/openshift-goimports || GOBIN=$(LOCALBIN) go install github.com/openshift-eng/openshift-goimports@latest OPERATOR_SDK_DL_URL := https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION) .PHONY: install-operator-sdk install-operator-sdk: $(OPERATOR_SDK) ## Download fixed version operator-sdk binary for consist outcome $(OPERATOR_SDK): $(LOCALBIN) - curl -L $(OPERATOR_SDK_DL_URL)/operator-sdk_$(shell go env GOOS)_$(shell go env GOARCH) --output-dir $(LOCALBIN) --output operator-sdk + curl -L $(OPERATOR_SDK_DL_URL)/operator-sdk_$(shell go env GOOS)_$(shell go env GOARCH) --output $(LOCALBIN)/operator-sdk chmod +x $(OPERATOR_SDK) .PHONY: validate-bundle @@ -314,10 +279,9 @@ validate-bundle: install-operator-sdk $(OPERATOR_SDK) bundle validate ./bundle --select-optional suite=operatorframework .PHONY: bundle -bundle: defaults manifests kustomize install-operator-sdk ## Generate bundle manifests and metadata, then validate generated files. +bundle: manifests kustomize install-operator-sdk ## Generate bundle manifests and metadata, then validate generated files. + cd config/manager && IMAGE=$(IMG) perl -i -pe 's/codeflare-operator-controller-image=(.*)$$/codeflare-operator-controller-image=$$ENV{"IMAGE"}/' params.env $(OPERATOR_SDK) generate kustomize manifests -q - $(KUSTOMIZE) fn run config/crd/mcad --image gcr.io/kpt-fn/apply-setters:v0.2.0 -- MCAD_CRD=$(MCAD_CRD) - cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) cd config/manifests && $(KUSTOMIZE) edit add patch --patch '[{"op":"add", "path":"/metadata/annotations/containerImage", "value": "$(IMG)" }]' --kind ClusterServiceVersion cd config/manifests && $(KUSTOMIZE) edit add patch --patch '[{"op":"add", "path":"/spec/replaces", "value": "codeflare-operator.$(PREVIOUS_VERSION)" }]' --kind ClusterServiceVersion $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) @@ -330,15 +294,15 @@ bundle-build: bundle ## Build the bundle image. .PHONY: bundle-push bundle-push: ## Push the bundle image. - $(MAKE) image-push IMG=$(BUNDLE_IMG) + podman push $(BUNDLE_IMG) $(BUNDLE_PUSH_OPT) .PHONY: openshift-community-operator-release openshift-community-operator-release: install-gh-cli bundle ## build bundle and create PR in OpenShift community operators repository - git clone https://$(GH_TOKEN)@github.com/$(OPERATORS_REPO_FORK_ORG)/community-operators-prod.git + git clone https://x-access-token:$(GH_TOKEN)@github.com/$(OPERATORS_REPO_FORK_ORG)/community-operators-prod.git cd community-operators-prod && git remote add upstream https://github.com/$(OPERATORS_REPO_ORG)/community-operators-prod.git && git pull upstream main && git push origin main cp -r bundle community-operators-prod/operators/codeflare-operator/$(BUNDLE_VERSION) - cd community-operators-prod && git checkout -b codeflare-release-$(BUNDLE_VERSION) && git add operators/codeflare-operator/$(BUNDLE_VERSION)/* && git commit -m "add bundle manifests codeflare version $(BUNDLE_VERSION)" && git push origin codeflare-release-$(BUNDLE_VERSION) - gh pr create --repo $(OPERATORS_REPO_FORK_ORG)/community-operators-prod --title "CodeFlare $(BUNDLE_VERSION)" --body "New release of codeflare operator" --head $(OPERATORS_REPO_ORG):codeflare-release-$(BUNDLE_VERSION) --base main + cd community-operators-prod && git checkout -b codeflare-release-$(BUNDLE_VERSION) && git add operators/codeflare-operator/$(BUNDLE_VERSION)/* && git commit -m "add bundle manifests codeflare version $(BUNDLE_VERSION)" --signoff && git push origin codeflare-release-$(BUNDLE_VERSION) + gh pr create --repo $(OPERATORS_REPO_ORG)/community-operators-prod --title "CodeFlare $(BUNDLE_VERSION)" --body "New release of codeflare operator" --head $(OPERATORS_REPO_FORK_ORG):codeflare-release-$(BUNDLE_VERSION) --base main rm -rf community-operators-prod .PHONY: opm @@ -377,11 +341,65 @@ endif catalog-build: opm ## Build a catalog image. $(OPM) index add --container-tool podman --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) +# Build a catalog image by adding bundle images to existing catalog using the operator package manager tool, 'opm'. +.PHONY: catalog-build-from-index +catalog-build-from-index: opm ## Build a catalog image. + mkdir catalog + $(OPM) render $(CATALOG_BASE_IMG) -o yaml > catalog/bundles.yaml + $(OPM) render $(BUNDLE_IMG) $(OPM_BUNDLE_OPT) > catalog/codeflare-operator-bundle.yaml + $(SED) -i -E "s/(.*)(- name: codeflare-operator.v0.2.0)/\1- name: codeflare-operator.$(VERSION)\n replaces: codeflare-operator.$(PREVIOUS_VERSION)\n\2/" catalog/bundles.yaml + $(OPM) validate catalog + $(OPM) generate dockerfile catalog + podman build . -f catalog.Dockerfile -t $(CATALOG_IMG) + # Push the catalog image. .PHONY: catalog-push catalog-push: ## Push a catalog image. - $(MAKE) image-push IMG=$(CATALOG_IMG) + podman push $(CATALOG_IMG) $(CATALOG_PUSH_OPT) .PHONY: test-unit -test-unit: defaults manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out +test-unit: manifests fmt vet envtest ## Run unit tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $(go list ./... | grep -v /test/) -coverprofile cover.out + +.PHONY: test-component +test-component: envtest ginkgo ## Run component tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) -v ./pkg/controllers/ + +.PHONY: test-e2e +test-e2e: manifests fmt vet ## Run e2e tests. + go test -timeout 30m -v ./test/e2e + +.PHONY: test-odh +test-odh: manifests fmt vet ## Run e2e ODH tests. + go test -timeout 60m -v ./test/odh + +.PHONY: store-odh-logs +store-odh-logs: # Store all ODH relevant logs into artifact directory + kubectl logs -n opendatahub deployment/codeflare-operator-manager > ${ARTIFACT_DIR}/codeflare-operator.log + kubectl logs -n opendatahub deployment/kuberay-operator > ${ARTIFACT_DIR}/kuberay-operator.log + kubectl logs -n openshift-operators deployment/opendatahub-operator-controller-manager > ${ARTIFACT_DIR}/odh-operator.log + kubectl get events -n opendatahub > ${ARTIFACT_DIR}/odh-events.log + +.PHONY: kind-e2e +kind-e2e: ## Set up e2e KinD cluster + test/e2e/kind.sh + +.PHONY: setup-e2e +setup-e2e: ## Set up e2e tests. + KUBERAY_VERSION=$(KUBERAY_VERSION) test/e2e/setup.sh + +.PHONY: imports +imports: openshift-goimports ## Organize imports in go files using openshift-goimports. Example: make imports + $(OPENSHIFT-GOIMPORTS) + +.PHONY: verify-imports +verify-imports: openshift-goimports ## Run import verifications. + ./hack/verify-imports.sh $(OPENSHIFT-GOIMPORTS) + +.PHONY: image-mnist-job-test-build +image-mnist-job-test-build: ## Build container image with the MNIST job. + podman build -t ${MNIST_JOB_TEST_IMG} ./test/pytorch_mnist_image + +.PHONY: image-mnist-job-test-push +image-mnist-job-test-push: image-mnist-job-test-build ## Push container image with the MNIST job. + podman push ${MNIST_JOB_TEST_IMG} diff --git a/OWNERS b/OWNERS index 58754041..955704b3 100644 --- a/OWNERS +++ b/OWNERS @@ -1,16 +1,19 @@ approvers: - anishasthana - astefanutti + - ChristianZaccaria - jbusche - kpostoffice - - maxusmusti + - sutaakar - tedhtchang reviewers: - anishasthana - astefanutti + - Bobbins228 + - ChristianZaccaria - dimakis + - Fiona-Waters - jbusche - kpostoffice - - maxusmusti - - MichaelClifford + - sutaakar - tedhtchang diff --git a/PROJECT b/PROJECT index 6ed09b51..965a62fd 100644 --- a/PROJECT +++ b/PROJECT @@ -1,3 +1,7 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: codeflare.dev layout: - go.kubebuilder.io/v3 @@ -7,22 +11,14 @@ plugins: projectName: codeflare-operator repo: github.com/project-codeflare/codeflare-operator resources: -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: codeflare.dev - group: codeflare - kind: MCAD - path: github.com/project-codeflare/codeflare-operator/api/v1alpha1 - version: v1alpha1 -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: codeflare.dev - group: codeflare - kind: InstaScale - path: github.com/project-codeflare/codeflare-operator/api/v1alpha1 - version: v1alpha1 +- controller: true + domain: ray.io + group: ray + kind: RayCluster + path: github.com/project-codeflare/codeflare-operator/pkg/controllers + version: v1 + webhooks: + defaulting: true + validation: true + webhookVersion: v1 version: "3" diff --git a/README.md b/README.md index afc9dafa..7531cfdd 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,124 @@ # codeflare-operator -Operator for installation and lifecycle management of CodeFlare distributed workload stack, starting with MCAD and InstaScale + +Operator for installation and lifecycle management of CodeFlare distributed workload stack. CodeFlare Stack Compatibility Matrix -| Component | Version | -|------------------------------|---------| -| CodeFlare Operator | v0.0.4 | -| Multi-Cluster App Dispatcher | v1.31.0 | -| CodeFlare-SDK | v0.4.4 | -| InstaScale | v0.0.4 | -| KubeRay | v0.5.0 | +| Component | Version | +|------------------------------|---------------------------------------------------------------------------------------------------| +| CodeFlare Operator | [v1.4.0](https://github.com/project-codeflare/codeflare-operator/releases/tag/v1.4.0) | +| CodeFlare-SDK | [v0.16.0](https://github.com/project-codeflare/codeflare-sdk/releases/tag/v0.16.0) | +| KubeRay | [v1.1.0](https://github.com/opendatahub-io/kuberay/releases/tag/v1.1.0) | -## Release process +## Development + +Requirements: +- GNU sed - sed is used in several Makefile command. Using macOS default sed is incompatible, so GNU sed is needed for correct execution of these commands. + When you have a version of the GNU sed installed on a macOS you may specify the binary using + ```bash + # brew install gnu-sed + make install -e SED=/usr/local/bin/gsed + ``` + +### Testing + +The e2e tests can be executed locally by running the following commands: + +1. Use an existing cluster, or set up a test cluster, e.g.: + + ```bash + # Create a KinD cluster + make kind-e2e + # Install the CRDs + make install + ``` + + [!NOTE] + Some e2e tests cover the access to services via Ingresses, as end-users would do, which requires access to the Ingress controller load balancer by its IP. + For it to work on macOS, this requires installing [docker-mac-net-connect](https://github.com/chipmk/docker-mac-net-connect). + +2. Start the operator locally: + + ```bash + NAMESPACE=default make run + ``` + + Alternatively, You can run the operator from your IDE / debugger. + +3. Set up the test CodeFlare stack: + + ```bash + make setup-e2e + ``` + + [!NOTE] + In OpenShift the KubeRay operator pod gets random user assigned. This user is then used to run Ray cluster. + However the random user assigned by OpenShift doesn't have rights to store dataset downloaded as part of test execution, causing tests to fail. + To prevent this failure on OpenShift user should enforce user 1000 for KubeRay and Ray cluster by creating this SCC in KubeRay operator namespace (replace the namespace placeholder): + + ```yaml + kind: SecurityContextConstraints + apiVersion: security.openshift.io/v1 + metadata: + name: run-as-ray-user + seLinuxContext: + type: MustRunAs + runAsUser: + type: MustRunAs + uid: 1000 + users: + - 'system:serviceaccount:$(namespace):kuberay-operator' + ``` + +4. In a separate terminal, set your output directory for test files, and run the e2e suite: + ```bash + export CODEFLARE_TEST_OUTPUT_DIR= + ``` + + ```bash + make test-e2e + ``` + + Alternatively, You can run the e2e test(s) from your IDE / debugger. + +#### Testing on disconnected cluster + +To properly run e2e tests on disconnected cluster user has to provide additional environment variables to properly configure testing environment: + +- `CODEFLARE_TEST_PYTORCH_IMAGE` - image tag for image used to run training job +- `CODEFLARE_TEST_RAY_IMAGE` - image tag for Ray cluster image +- `MNIST_DATASET_URL` - URL where MNIST dataset is available +- `PIP_INDEX_URL` - URL where PyPI server with needed dependencies is running +- `PIP_TRUSTED_HOST` - PyPI server hostname -Prerequisite: -- Build and release [MCAD](https://github.com/project-codeflare/multi-cluster-app-dispatcher) -- Build and release [InstaScale](https://github.com/project-codeflare/instascale) -- Build and release [CodeFlare-SDK](https://github.com/project-codeflare/codeflare-sdk) +For ODH tests additional environment variables are needed: -Release steps: -1. Invoke [tag-and-build.yml](https://github.com/project-codeflare/codeflare-operator/actions/workflows/tag-and-build.yml) GitHub action, this action will create a repository tag, build and push operator image. +- `NOTEBOOK_IMAGE_STREAM_NAME` - name of the ODH Notebook ImageStream to be used +- `ODH_NAMESPACE` - namespace where ODH is installed -2. Check result of [tag-and-build.yml](https://github.com/project-codeflare/codeflare-operator/actions/workflows/tag-and-build.yml) GitHub action, it should pass. +## Release -3. Verify that compatibility matrix in [README](https://github.com/project-codeflare/codeflare-operator/blob/main/README.md) was properly updated. +1. Invoke [project-codeflare-release.yaml](https://github.com/project-codeflare/codeflare-operator/actions/workflows/project-codeflare-release.yml) +2. Once all jobs within the action are completed, verify that compatibility matrix in [README](https://github.com/project-codeflare/codeflare-operator/blob/main/README.md) was properly updated. +3. Verify that opened pull request to [OpenShift community operators repository](https://github.com/redhat-openshift-ecosystem/community-operators-prod) has proper content. +4. Once PR is merged, announce the new release in slack and mail lists, if any. +5. Release automation should open a PR with changes in [ODH CodeFlare operator repo](https://github.com/opendatahub-io/codeflare-operator). Review the changes proposed by automation. If all the changes are correct then manually cherrypick all `CARRY` and `PATCH` commits from the current main branch, push the result to a dedicated branch and ask on Slack channel for review of the result branch content. Once agreed then push the changes directly to the `main` branch (branch protection has to be temporarily disabled). +6. Build ODH/CFO image by triggering [Build and Push action](https://github.com/opendatahub-io/codeflare-operator/actions/workflows/build-and-push.yaml) +7. Create a release branch on [Red Hat CodeFlare operator repo](https://github.com/red-hat-data-services/codeflare-operator) for the next release if it doesn't exist yet. +8. Create a dedicated branch containing changes from [ODH CodeFlare operator repo](https://github.com/opendatahub-io/codeflare-operator). Cherrypick all relevant changes available in [Red Hat CodeFlare operator repo](https://github.com/red-hat-data-services/codeflare-operator) latest release branch which should be available also in the next release. Ask on Slack channel for review of the result branch content. Once agreed then push the changes directly to the release branch. +9. Make sure that release automation created a PR updating CodeFlare SDK version in [ODH Notebooks repository](https://github.com/opendatahub-io/notebooks). Make sure the PR gets merged. -4. Verify that opened pull request to [OpenShift community operators repository](https://github.com/redhat-openshift-ecosystem/community-operators-prod) has proper content. +### Releases involving part of the stack -5. Once PR is merged, update component stable tags to point at the latest image release. +There may be instances in which a new CodeFlare stack release requires releases of only a subset of the stack components. Examples could be hotfixes for a specific component. In these instances: -6. Announce the new release in slack and mail lists, if any. +1. Build updated components as needed: + - Build and release [CodeFlare-SDK](https://github.com/project-codeflare/codeflare-sdk) -7. Update the Distributed Workloads component in ODH (also copy/update the compatibility matrix). +2. Invoke [tag-and-build.yml](https://github.com/project-codeflare/codeflare-operator/actions/workflows/tag-and-build.yml) GitHub action, this action will create a repository tag, build and push operator image. +3. Check result of [tag-and-build.yml](https://github.com/project-codeflare/codeflare-operator/actions/workflows/tag-and-build.yml) GitHub action, it should pass. +4. Verify that compatibility matrix in [README](https://github.com/project-codeflare/codeflare-operator/blob/main/README.md) was properly updated. +5. Follow the steps 3-6 from the previous section. diff --git a/api/codeflare/v1alpha1/doc.go b/api/codeflare/v1alpha1/doc.go deleted file mode 100644 index 13be1de4..00000000 --- a/api/codeflare/v1alpha1/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// +k8s:deepcopy-gen=package,register -// +kubebuilder:object:generate=true -// +groupName=codeflare.codeflare.dev - -package v1alpha1 diff --git a/api/codeflare/v1alpha1/instascale_types.go b/api/codeflare/v1alpha1/instascale_types.go deleted file mode 100644 index 7368cb1a..00000000 --- a/api/codeflare/v1alpha1/instascale_types.go +++ /dev/null @@ -1,83 +0,0 @@ -/* -Copyright 2023. - -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 ( - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// InstaScaleSpec defines the desired state of InstaScale -type InstaScaleSpec struct { - - // enableMonitoring determines if monitoring artifacts are deployed for the InstaScale instance. - // +kubebuilder:default=true - EnableMonitoring bool `json:"enableMonitoring,omitempty"` - - // maxScaleoutAllowed determines the max number of machines that can be scaled up by InstaScale - // +kubebuilder:default=15 - MaxScaleoutAllowed int `json:"maxScaleoutAllowed,omitempty"` - - // useMachinePools determines whether InstaScale should use MachineSets or MachinePools for scaling - // +kubebuilder:default=false - UseMachinePools bool `json:"useMachinePools,omitempty"` - - // controllerResources determines the container resources for the InstaScale controller deployment - ControllerResources *v1.ResourceRequirements `json:"controllerResources,omitempty"` - - // The container image for the InstaScale controller deployment. - // If specified, the provided container image must be compatible with the running CodeFlare operator. - // Using an incompatible, or unrelated container image, will result in an undefined behavior. - // A CodeFlare operator upgrade will not upgrade the InstaScale controller, that'll keep running this - // specified container image. - // If not specified, the latest version compatible with the running CodeFlare operator is used. - // A CodeFlare operator upgrade may upgrade the InstaScale controller to a newer container image. - // - // +optional - ControllerImage string `json:"controllerImage,omitempty"` -} - -// InstaScaleStatus defines the observed state of InstaScale -type InstaScaleStatus struct { - // Important: Run "make" to regenerate code after modifying this file - - // +kubebuilder:default=false - Ready bool `json:"ready"` -} - -// +genclient -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status - -// InstaScale is the Schema for the instascales API -// +operator-sdk:csv:customresourcedefinitions:displayName="InstaScale" -type InstaScale struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec InstaScaleSpec `json:"spec,omitempty"` - Status InstaScaleStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// InstaScaleList contains a list of InstaScale -type InstaScaleList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []InstaScale `json:"items"` -} diff --git a/api/codeflare/v1alpha1/mcad_types.go b/api/codeflare/v1alpha1/mcad_types.go deleted file mode 100644 index dc22291f..00000000 --- a/api/codeflare/v1alpha1/mcad_types.go +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright 2023. - -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 ( - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// MCADSpec defines the desired state of MCAD -type MCADSpec struct { - // EnableMonitoring determines if monitoring artifacts are deployed for the MCAD instance. - // +kubebuilder:default=true - EnableMonitoring bool `json:"enableMonitoring,omitempty"` - - // MultiCluster determines if MCAD will be routing traffic to multiple clusters. - // +kubebuilder:default=false - MultiCluster bool `json:"multiCluster,omitempty"` - - // DispatcherMode determines whether the MCAD Controller should be launched in Dispatcher mode. - // +kubebuilder:default=false - DispatcherMode bool `json:"dispatcherMode,omitempty"` - - // PreemptionEnabled determines if scheduled jobs can be preempted for others - // +kubebuilder:default=false - PreemptionEnabled bool `json:"preemptionEnabled,omitempty"` - - // AgentConfigs determine paths to agent config file:deploymentName separated by commas(,). - AgentConfigs string `json:"agentConfigs,omitempty"` - - // QuotaRestURL determines URL for Rest quota management. - QuotaRestURL string `json:"quotaRestURL,omitempty"` - - // PodCreationTimeout determines timeout in milliseconds for pods to be created after dispatching job. - // +kubebuilder:default=-1 - PodCreationTimeout int `json:"podCreationTimeout,omitempty"` - // podCreationTimeout: //int (default blank) - - // ControllerResources defines the cpu and memory resource requirements for the MCAD Controller - // +kubebuilder:default={} - ControllerResources v1.ResourceRequirements `json:"controllerResources,omitempty" protobuf:"bytes,8,opt"` - - // The container image for the MCAD controller deployment. - // If specified, the provided container image must be compatible with the running CodeFlare operator. - // Using an incompatible, or unrelated container image, will result in an undefined behavior. - // A CodeFlare operator upgrade will not upgrade the MCAD controller, that'll keep running this - // specified container image. - // If not specified, the latest version compatible with the running CodeFlare operator is used. - // A CodeFlare operator upgrade may upgrade the MCAD controller to a newer container image. - // - // +optional - ControllerImage string `json:"controllerImage,omitempty"` -} - -// MCADStatus defines the observed state of MCAD -type MCADStatus struct { - // Important: Run "make" to regenerate code after modifying this file - - // Ready indicates whether the application is ready to serve requests - Ready bool `json:"ready"` -} - -// +genclient -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status - -// MCAD is the Schema for the mcads API -type MCAD struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec MCADSpec `json:"spec,omitempty"` - Status MCADStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// MCADList contains a list of MCAD -type MCADList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []MCAD `json:"items"` -} diff --git a/api/codeflare/v1alpha1/register.go b/api/codeflare/v1alpha1/register.go deleted file mode 100644 index 12bd3997..00000000 --- a/api/codeflare/v1alpha1/register.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2023. - -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" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// Kind takes an unqualified kind and returns back a Group qualified GroupKind. -func Kind(kind string) schema.GroupKind { - return SchemeGroupVersion.WithKind(kind).GroupKind() -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource. -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -var ( - SchemeGroupVersion = schema.GroupVersion{Group: "codeflare.codeflare.dev", Version: "v1alpha1"} - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme -) - -// Adds the list of known types to Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &MCAD{}, - &MCADList{}, - &InstaScale{}, - &InstaScaleList{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/api/codeflare/v1alpha1/zz_generated.deepcopy.go b/api/codeflare/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 5f0dd24a..00000000 --- a/api/codeflare/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,211 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -/* -Copyright 2023. - -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/api/core/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 *InstaScale) DeepCopyInto(out *InstaScale) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstaScale. -func (in *InstaScale) DeepCopy() *InstaScale { - if in == nil { - return nil - } - out := new(InstaScale) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InstaScale) 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 *InstaScaleList) DeepCopyInto(out *InstaScaleList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]InstaScale, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstaScaleList. -func (in *InstaScaleList) DeepCopy() *InstaScaleList { - if in == nil { - return nil - } - out := new(InstaScaleList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InstaScaleList) 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 *InstaScaleSpec) DeepCopyInto(out *InstaScaleSpec) { - *out = *in - if in.ControllerResources != nil { - in, out := &in.ControllerResources, &out.ControllerResources - *out = new(v1.ResourceRequirements) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstaScaleSpec. -func (in *InstaScaleSpec) DeepCopy() *InstaScaleSpec { - if in == nil { - return nil - } - out := new(InstaScaleSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InstaScaleStatus) DeepCopyInto(out *InstaScaleStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstaScaleStatus. -func (in *InstaScaleStatus) DeepCopy() *InstaScaleStatus { - if in == nil { - return nil - } - out := new(InstaScaleStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MCAD) DeepCopyInto(out *MCAD) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MCAD. -func (in *MCAD) DeepCopy() *MCAD { - if in == nil { - return nil - } - out := new(MCAD) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MCAD) 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 *MCADList) DeepCopyInto(out *MCADList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]MCAD, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MCADList. -func (in *MCADList) DeepCopy() *MCADList { - if in == nil { - return nil - } - out := new(MCADList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *MCADList) 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 *MCADSpec) DeepCopyInto(out *MCADSpec) { - *out = *in - in.ControllerResources.DeepCopyInto(&out.ControllerResources) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MCADSpec. -func (in *MCADSpec) DeepCopy() *MCADSpec { - if in == nil { - return nil - } - out := new(MCADSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MCADStatus) DeepCopyInto(out *MCADStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MCADStatus. -func (in *MCADStatus) DeepCopy() *MCADStatus { - if in == nil { - return nil - } - out := new(MCADStatus) - in.DeepCopyInto(out) - return out -} diff --git a/client/applyconfiguration/codeflare/v1alpha1/instascale.go b/client/applyconfiguration/codeflare/v1alpha1/instascale.go deleted file mode 100644 index 3cb4c8c6..00000000 --- a/client/applyconfiguration/codeflare/v1alpha1/instascale.go +++ /dev/null @@ -1,219 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - v1 "k8s.io/client-go/applyconfigurations/meta/v1" -) - -// InstaScaleApplyConfiguration represents an declarative configuration of the InstaScale type for use -// with apply. -type InstaScaleApplyConfiguration struct { - v1.TypeMetaApplyConfiguration `json:",inline"` - *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` - Spec *InstaScaleSpecApplyConfiguration `json:"spec,omitempty"` - Status *InstaScaleStatusApplyConfiguration `json:"status,omitempty"` -} - -// InstaScale constructs an declarative configuration of the InstaScale type for use with -// apply. -func InstaScale(name, namespace string) *InstaScaleApplyConfiguration { - b := &InstaScaleApplyConfiguration{} - b.WithName(name) - b.WithNamespace(namespace) - b.WithKind("InstaScale") - b.WithAPIVersion("codeflare.codeflare.dev/v1alpha1") - return b -} - -// WithKind sets the Kind field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Kind field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithKind(value string) *InstaScaleApplyConfiguration { - b.Kind = &value - return b -} - -// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the APIVersion field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithAPIVersion(value string) *InstaScaleApplyConfiguration { - b.APIVersion = &value - return b -} - -// WithName sets the Name field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Name field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithName(value string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.Name = &value - return b -} - -// WithGenerateName sets the GenerateName field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the GenerateName field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithGenerateName(value string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.GenerateName = &value - return b -} - -// WithNamespace sets the Namespace field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Namespace field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithNamespace(value string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.Namespace = &value - return b -} - -// WithUID sets the UID field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the UID field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithUID(value types.UID) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.UID = &value - return b -} - -// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ResourceVersion field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithResourceVersion(value string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.ResourceVersion = &value - return b -} - -// WithGeneration sets the Generation field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Generation field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithGeneration(value int64) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.Generation = &value - return b -} - -// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the CreationTimestamp field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithCreationTimestamp(value metav1.Time) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.CreationTimestamp = &value - return b -} - -// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the DeletionTimestamp field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.DeletionTimestamp = &value - return b -} - -// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.DeletionGracePeriodSeconds = &value - return b -} - -// WithLabels puts the entries into the Labels field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, the entries provided by each call will be put on the Labels field, -// overwriting an existing map entries in Labels field with the same key. -func (b *InstaScaleApplyConfiguration) WithLabels(entries map[string]string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - if b.Labels == nil && len(entries) > 0 { - b.Labels = make(map[string]string, len(entries)) - } - for k, v := range entries { - b.Labels[k] = v - } - return b -} - -// WithAnnotations puts the entries into the Annotations field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, the entries provided by each call will be put on the Annotations field, -// overwriting an existing map entries in Annotations field with the same key. -func (b *InstaScaleApplyConfiguration) WithAnnotations(entries map[string]string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - if b.Annotations == nil && len(entries) > 0 { - b.Annotations = make(map[string]string, len(entries)) - } - for k, v := range entries { - b.Annotations[k] = v - } - return b -} - -// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the OwnerReferences field. -func (b *InstaScaleApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - for i := range values { - if values[i] == nil { - panic("nil value passed to WithOwnerReferences") - } - b.OwnerReferences = append(b.OwnerReferences, *values[i]) - } - return b -} - -// WithFinalizers adds the given value to the Finalizers field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the Finalizers field. -func (b *InstaScaleApplyConfiguration) WithFinalizers(values ...string) *InstaScaleApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - for i := range values { - b.Finalizers = append(b.Finalizers, values[i]) - } - return b -} - -func (b *InstaScaleApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { - if b.ObjectMetaApplyConfiguration == nil { - b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} - } -} - -// WithSpec sets the Spec field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Spec field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithSpec(value *InstaScaleSpecApplyConfiguration) *InstaScaleApplyConfiguration { - b.Spec = value - return b -} - -// WithStatus sets the Status field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Status field is set to the value of the last call. -func (b *InstaScaleApplyConfiguration) WithStatus(value *InstaScaleStatusApplyConfiguration) *InstaScaleApplyConfiguration { - b.Status = value - return b -} diff --git a/client/applyconfiguration/codeflare/v1alpha1/instascalespec.go b/client/applyconfiguration/codeflare/v1alpha1/instascalespec.go deleted file mode 100644 index e6ed5abd..00000000 --- a/client/applyconfiguration/codeflare/v1alpha1/instascalespec.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/v1" -) - -// InstaScaleSpecApplyConfiguration represents an declarative configuration of the InstaScaleSpec type for use -// with apply. -type InstaScaleSpecApplyConfiguration struct { - EnableMonitoring *bool `json:"enableMonitoring,omitempty"` - MaxScaleoutAllowed *int `json:"maxScaleoutAllowed,omitempty"` - UseMachinePools *bool `json:"useMachinePools,omitempty"` - ControllerResources *v1.ResourceRequirements `json:"controllerResources,omitempty"` - ControllerImage *string `json:"controllerImage,omitempty"` -} - -// InstaScaleSpecApplyConfiguration constructs an declarative configuration of the InstaScaleSpec type for use with -// apply. -func InstaScaleSpec() *InstaScaleSpecApplyConfiguration { - return &InstaScaleSpecApplyConfiguration{} -} - -// WithEnableMonitoring sets the EnableMonitoring field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the EnableMonitoring field is set to the value of the last call. -func (b *InstaScaleSpecApplyConfiguration) WithEnableMonitoring(value bool) *InstaScaleSpecApplyConfiguration { - b.EnableMonitoring = &value - return b -} - -// WithMaxScaleoutAllowed sets the MaxScaleoutAllowed field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the MaxScaleoutAllowed field is set to the value of the last call. -func (b *InstaScaleSpecApplyConfiguration) WithMaxScaleoutAllowed(value int) *InstaScaleSpecApplyConfiguration { - b.MaxScaleoutAllowed = &value - return b -} - -// WithUseMachinePools sets the UseMachinePools field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the UseMachinePools field is set to the value of the last call. -func (b *InstaScaleSpecApplyConfiguration) WithUseMachinePools(value bool) *InstaScaleSpecApplyConfiguration { - b.UseMachinePools = &value - return b -} - -// WithControllerResources sets the ControllerResources field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ControllerResources field is set to the value of the last call. -func (b *InstaScaleSpecApplyConfiguration) WithControllerResources(value v1.ResourceRequirements) *InstaScaleSpecApplyConfiguration { - b.ControllerResources = &value - return b -} - -// WithControllerImage sets the ControllerImage field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ControllerImage field is set to the value of the last call. -func (b *InstaScaleSpecApplyConfiguration) WithControllerImage(value string) *InstaScaleSpecApplyConfiguration { - b.ControllerImage = &value - return b -} diff --git a/client/applyconfiguration/codeflare/v1alpha1/instascalestatus.go b/client/applyconfiguration/codeflare/v1alpha1/instascalestatus.go deleted file mode 100644 index 9643218f..00000000 --- a/client/applyconfiguration/codeflare/v1alpha1/instascalestatus.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -// InstaScaleStatusApplyConfiguration represents an declarative configuration of the InstaScaleStatus type for use -// with apply. -type InstaScaleStatusApplyConfiguration struct { - Ready *bool `json:"ready,omitempty"` -} - -// InstaScaleStatusApplyConfiguration constructs an declarative configuration of the InstaScaleStatus type for use with -// apply. -func InstaScaleStatus() *InstaScaleStatusApplyConfiguration { - return &InstaScaleStatusApplyConfiguration{} -} - -// WithReady sets the Ready field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Ready field is set to the value of the last call. -func (b *InstaScaleStatusApplyConfiguration) WithReady(value bool) *InstaScaleStatusApplyConfiguration { - b.Ready = &value - return b -} diff --git a/client/applyconfiguration/codeflare/v1alpha1/mcad.go b/client/applyconfiguration/codeflare/v1alpha1/mcad.go deleted file mode 100644 index 0b7a441b..00000000 --- a/client/applyconfiguration/codeflare/v1alpha1/mcad.go +++ /dev/null @@ -1,219 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - v1 "k8s.io/client-go/applyconfigurations/meta/v1" -) - -// MCADApplyConfiguration represents an declarative configuration of the MCAD type for use -// with apply. -type MCADApplyConfiguration struct { - v1.TypeMetaApplyConfiguration `json:",inline"` - *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` - Spec *MCADSpecApplyConfiguration `json:"spec,omitempty"` - Status *MCADStatusApplyConfiguration `json:"status,omitempty"` -} - -// MCAD constructs an declarative configuration of the MCAD type for use with -// apply. -func MCAD(name, namespace string) *MCADApplyConfiguration { - b := &MCADApplyConfiguration{} - b.WithName(name) - b.WithNamespace(namespace) - b.WithKind("MCAD") - b.WithAPIVersion("codeflare.codeflare.dev/v1alpha1") - return b -} - -// WithKind sets the Kind field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Kind field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithKind(value string) *MCADApplyConfiguration { - b.Kind = &value - return b -} - -// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the APIVersion field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithAPIVersion(value string) *MCADApplyConfiguration { - b.APIVersion = &value - return b -} - -// WithName sets the Name field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Name field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithName(value string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.Name = &value - return b -} - -// WithGenerateName sets the GenerateName field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the GenerateName field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithGenerateName(value string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.GenerateName = &value - return b -} - -// WithNamespace sets the Namespace field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Namespace field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithNamespace(value string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.Namespace = &value - return b -} - -// WithUID sets the UID field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the UID field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithUID(value types.UID) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.UID = &value - return b -} - -// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ResourceVersion field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithResourceVersion(value string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.ResourceVersion = &value - return b -} - -// WithGeneration sets the Generation field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Generation field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithGeneration(value int64) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.Generation = &value - return b -} - -// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the CreationTimestamp field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithCreationTimestamp(value metav1.Time) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.CreationTimestamp = &value - return b -} - -// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the DeletionTimestamp field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.DeletionTimestamp = &value - return b -} - -// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - b.DeletionGracePeriodSeconds = &value - return b -} - -// WithLabels puts the entries into the Labels field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, the entries provided by each call will be put on the Labels field, -// overwriting an existing map entries in Labels field with the same key. -func (b *MCADApplyConfiguration) WithLabels(entries map[string]string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - if b.Labels == nil && len(entries) > 0 { - b.Labels = make(map[string]string, len(entries)) - } - for k, v := range entries { - b.Labels[k] = v - } - return b -} - -// WithAnnotations puts the entries into the Annotations field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, the entries provided by each call will be put on the Annotations field, -// overwriting an existing map entries in Annotations field with the same key. -func (b *MCADApplyConfiguration) WithAnnotations(entries map[string]string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - if b.Annotations == nil && len(entries) > 0 { - b.Annotations = make(map[string]string, len(entries)) - } - for k, v := range entries { - b.Annotations[k] = v - } - return b -} - -// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the OwnerReferences field. -func (b *MCADApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - for i := range values { - if values[i] == nil { - panic("nil value passed to WithOwnerReferences") - } - b.OwnerReferences = append(b.OwnerReferences, *values[i]) - } - return b -} - -// WithFinalizers adds the given value to the Finalizers field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the Finalizers field. -func (b *MCADApplyConfiguration) WithFinalizers(values ...string) *MCADApplyConfiguration { - b.ensureObjectMetaApplyConfigurationExists() - for i := range values { - b.Finalizers = append(b.Finalizers, values[i]) - } - return b -} - -func (b *MCADApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { - if b.ObjectMetaApplyConfiguration == nil { - b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} - } -} - -// WithSpec sets the Spec field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Spec field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithSpec(value *MCADSpecApplyConfiguration) *MCADApplyConfiguration { - b.Spec = value - return b -} - -// WithStatus sets the Status field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Status field is set to the value of the last call. -func (b *MCADApplyConfiguration) WithStatus(value *MCADStatusApplyConfiguration) *MCADApplyConfiguration { - b.Status = value - return b -} diff --git a/client/applyconfiguration/codeflare/v1alpha1/mcadspec.go b/client/applyconfiguration/codeflare/v1alpha1/mcadspec.go deleted file mode 100644 index c7cb170a..00000000 --- a/client/applyconfiguration/codeflare/v1alpha1/mcadspec.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1 "k8s.io/api/core/v1" -) - -// MCADSpecApplyConfiguration represents an declarative configuration of the MCADSpec type for use -// with apply. -type MCADSpecApplyConfiguration struct { - EnableMonitoring *bool `json:"enableMonitoring,omitempty"` - MultiCluster *bool `json:"multiCluster,omitempty"` - DispatcherMode *bool `json:"dispatcherMode,omitempty"` - PreemptionEnabled *bool `json:"preemptionEnabled,omitempty"` - AgentConfigs *string `json:"agentConfigs,omitempty"` - QuotaRestURL *string `json:"quotaRestURL,omitempty"` - PodCreationTimeout *int `json:"podCreationTimeout,omitempty"` - ControllerResources *v1.ResourceRequirements `json:"controllerResources,omitempty"` -} - -// MCADSpecApplyConfiguration constructs an declarative configuration of the MCADSpec type for use with -// apply. -func MCADSpec() *MCADSpecApplyConfiguration { - return &MCADSpecApplyConfiguration{} -} - -// WithEnableMonitoring sets the EnableMonitoring field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the EnableMonitoring field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithEnableMonitoring(value bool) *MCADSpecApplyConfiguration { - b.EnableMonitoring = &value - return b -} - -// WithMultiCluster sets the MultiCluster field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the MultiCluster field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithMultiCluster(value bool) *MCADSpecApplyConfiguration { - b.MultiCluster = &value - return b -} - -// WithDispatcherMode sets the DispatcherMode field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the DispatcherMode field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithDispatcherMode(value bool) *MCADSpecApplyConfiguration { - b.DispatcherMode = &value - return b -} - -// WithPreemptionEnabled sets the PreemptionEnabled field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the PreemptionEnabled field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithPreemptionEnabled(value bool) *MCADSpecApplyConfiguration { - b.PreemptionEnabled = &value - return b -} - -// WithAgentConfigs sets the AgentConfigs field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the AgentConfigs field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithAgentConfigs(value string) *MCADSpecApplyConfiguration { - b.AgentConfigs = &value - return b -} - -// WithQuotaRestURL sets the QuotaRestURL field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the QuotaRestURL field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithQuotaRestURL(value string) *MCADSpecApplyConfiguration { - b.QuotaRestURL = &value - return b -} - -// WithPodCreationTimeout sets the PodCreationTimeout field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the PodCreationTimeout field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithPodCreationTimeout(value int) *MCADSpecApplyConfiguration { - b.PodCreationTimeout = &value - return b -} - -// WithControllerResources sets the ControllerResources field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ControllerResources field is set to the value of the last call. -func (b *MCADSpecApplyConfiguration) WithControllerResources(value v1.ResourceRequirements) *MCADSpecApplyConfiguration { - b.ControllerResources = &value - return b -} diff --git a/client/applyconfiguration/codeflare/v1alpha1/mcadstatus.go b/client/applyconfiguration/codeflare/v1alpha1/mcadstatus.go deleted file mode 100644 index 0b93b070..00000000 --- a/client/applyconfiguration/codeflare/v1alpha1/mcadstatus.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -// MCADStatusApplyConfiguration represents an declarative configuration of the MCADStatus type for use -// with apply. -type MCADStatusApplyConfiguration struct { - Ready *bool `json:"ready,omitempty"` -} - -// MCADStatusApplyConfiguration constructs an declarative configuration of the MCADStatus type for use with -// apply. -func MCADStatus() *MCADStatusApplyConfiguration { - return &MCADStatusApplyConfiguration{} -} - -// WithReady sets the Ready field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Ready field is set to the value of the last call. -func (b *MCADStatusApplyConfiguration) WithReady(value bool) *MCADStatusApplyConfiguration { - b.Ready = &value - return b -} diff --git a/client/applyconfiguration/internal/internal.go b/client/applyconfiguration/internal/internal.go deleted file mode 100644 index e3bfb7d5..00000000 --- a/client/applyconfiguration/internal/internal.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package internal - -import ( - "fmt" - "sync" - - typed "sigs.k8s.io/structured-merge-diff/v4/typed" -) - -func Parser() *typed.Parser { - parserOnce.Do(func() { - var err error - parser, err = typed.NewParser(schemaYAML) - if err != nil { - panic(fmt.Sprintf("Failed to parse schema: %v", err)) - } - }) - return parser -} - -var parserOnce sync.Once -var parser *typed.Parser -var schemaYAML = typed.YAMLObject(`types: -- name: __untyped_atomic_ - scalar: untyped - list: - elementType: - namedType: __untyped_atomic_ - elementRelationship: atomic - map: - elementType: - namedType: __untyped_atomic_ - elementRelationship: atomic -- name: __untyped_deduced_ - scalar: untyped - list: - elementType: - namedType: __untyped_atomic_ - elementRelationship: atomic - map: - elementType: - namedType: __untyped_deduced_ - elementRelationship: separable -`) diff --git a/client/applyconfiguration/utils.go b/client/applyconfiguration/utils.go deleted file mode 100644 index fd87ac36..00000000 --- a/client/applyconfiguration/utils.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package applyconfiguration - -import ( - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/applyconfiguration/codeflare/v1alpha1" - schema "k8s.io/apimachinery/pkg/runtime/schema" -) - -// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no -// apply configuration type exists for the given GroupVersionKind. -func ForKind(kind schema.GroupVersionKind) interface{} { - switch kind { - // Group=codeflare.codeflare.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithKind("InstaScale"): - return &codeflarev1alpha1.InstaScaleApplyConfiguration{} - case v1alpha1.SchemeGroupVersion.WithKind("InstaScaleSpec"): - return &codeflarev1alpha1.InstaScaleSpecApplyConfiguration{} - case v1alpha1.SchemeGroupVersion.WithKind("InstaScaleStatus"): - return &codeflarev1alpha1.InstaScaleStatusApplyConfiguration{} - case v1alpha1.SchemeGroupVersion.WithKind("MCAD"): - return &codeflarev1alpha1.MCADApplyConfiguration{} - case v1alpha1.SchemeGroupVersion.WithKind("MCADSpec"): - return &codeflarev1alpha1.MCADSpecApplyConfiguration{} - case v1alpha1.SchemeGroupVersion.WithKind("MCADStatus"): - return &codeflarev1alpha1.MCADStatusApplyConfiguration{} - - } - return nil -} diff --git a/client/clientset/versioned/clientset.go b/client/clientset/versioned/clientset.go deleted file mode 100644 index 1d91a664..00000000 --- a/client/clientset/versioned/clientset.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package versioned - -import ( - "fmt" - "net/http" - - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/typed/codeflare/v1alpha1" - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - CodeflareV1alpha1() codeflarev1alpha1.CodeflareV1alpha1Interface -} - -// Clientset contains the clients for groups. -type Clientset struct { - *discovery.DiscoveryClient - codeflareV1alpha1 *codeflarev1alpha1.CodeflareV1alpha1Client -} - -// CodeflareV1alpha1 retrieves the CodeflareV1alpha1Client -func (c *Clientset) CodeflareV1alpha1() codeflarev1alpha1.CodeflareV1alpha1Interface { - return c.codeflareV1alpha1 -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -// If config's RateLimiter is not set and QPS and Burst are acceptable, -// NewForConfig will generate a rate-limiter in configShallowCopy. -// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), -// where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - - if configShallowCopy.UserAgent == "" { - configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() - } - - // share the transport between all clients - httpClient, err := rest.HTTPClientFor(&configShallowCopy) - if err != nil { - return nil, err - } - - return NewForConfigAndClient(&configShallowCopy, httpClient) -} - -// NewForConfigAndClient creates a new Clientset for the given config and http client. -// Note the http client provided takes precedence over the configured transport values. -// If config's RateLimiter is not set and QPS and Burst are acceptable, -// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. -func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - if configShallowCopy.Burst <= 0 { - return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") - } - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - - var cs Clientset - var err error - cs.codeflareV1alpha1, err = codeflarev1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - cs, err := NewForConfig(c) - if err != nil { - panic(err) - } - return cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.codeflareV1alpha1 = codeflarev1alpha1.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/client/clientset/versioned/fake/clientset_generated.go b/client/clientset/versioned/fake/clientset_generated.go deleted file mode 100644 index fbbb80dc..00000000 --- a/client/clientset/versioned/fake/clientset_generated.go +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - clientset "github.com/project-codeflare/codeflare-operator/client/clientset/versioned" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/typed/codeflare/v1alpha1" - fakecodeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/typed/codeflare/v1alpha1/fake" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{tracker: o} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery - tracker testing.ObjectTracker -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -func (c *Clientset) Tracker() testing.ObjectTracker { - return c.tracker -} - -var ( - _ clientset.Interface = &Clientset{} - _ testing.FakeClient = &Clientset{} -) - -// CodeflareV1alpha1 retrieves the CodeflareV1alpha1Client -func (c *Clientset) CodeflareV1alpha1() codeflarev1alpha1.CodeflareV1alpha1Interface { - return &fakecodeflarev1alpha1.FakeCodeflareV1alpha1{Fake: &c.Fake} -} diff --git a/client/clientset/versioned/fake/register.go b/client/clientset/versioned/fake/register.go deleted file mode 100644 index 4ff1cb3a..00000000 --- a/client/clientset/versioned/fake/register.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) - -var localSchemeBuilder = runtime.SchemeBuilder{ - codeflarev1alpha1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/client/clientset/versioned/scheme/doc.go b/client/clientset/versioned/scheme/doc.go deleted file mode 100644 index 5f6297fd..00000000 --- a/client/clientset/versioned/scheme/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/client/clientset/versioned/scheme/register.go b/client/clientset/versioned/scheme/register.go deleted file mode 100644 index 743173ce..00000000 --- a/client/clientset/versioned/scheme/register.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package scheme - -import ( - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - codeflarev1alpha1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(Scheme)) -} diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/codeflare_client.go b/client/clientset/versioned/typed/codeflare/v1alpha1/codeflare_client.go deleted file mode 100644 index 4b93fe6f..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/codeflare_client.go +++ /dev/null @@ -1,112 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "net/http" - - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/scheme" - rest "k8s.io/client-go/rest" -) - -type CodeflareV1alpha1Interface interface { - RESTClient() rest.Interface - InstaScalesGetter - MCADsGetter -} - -// CodeflareV1alpha1Client is used to interact with features provided by the codeflare.codeflare.dev group. -type CodeflareV1alpha1Client struct { - restClient rest.Interface -} - -func (c *CodeflareV1alpha1Client) InstaScales(namespace string) InstaScaleInterface { - return newInstaScales(c, namespace) -} - -func (c *CodeflareV1alpha1Client) MCADs(namespace string) MCADInterface { - return newMCADs(c, namespace) -} - -// NewForConfig creates a new CodeflareV1alpha1Client for the given config. -// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), -// where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*CodeflareV1alpha1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - httpClient, err := rest.HTTPClientFor(&config) - if err != nil { - return nil, err - } - return NewForConfigAndClient(&config, httpClient) -} - -// NewForConfigAndClient creates a new CodeflareV1alpha1Client for the given config and http client. -// Note the http client provided takes precedence over the configured transport values. -func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CodeflareV1alpha1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientForConfigAndClient(&config, h) - if err != nil { - return nil, err - } - return &CodeflareV1alpha1Client{client}, nil -} - -// NewForConfigOrDie creates a new CodeflareV1alpha1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *CodeflareV1alpha1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new CodeflareV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *CodeflareV1alpha1Client { - return &CodeflareV1alpha1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1alpha1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *CodeflareV1alpha1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/doc.go b/client/clientset/versioned/typed/codeflare/v1alpha1/doc.go deleted file mode 100644 index cf7c1520..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1alpha1 diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/doc.go b/client/clientset/versioned/typed/codeflare/v1alpha1/fake/doc.go deleted file mode 100644 index 7c26ebe2..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_codeflare_client.go b/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_codeflare_client.go deleted file mode 100644 index 9e234aca..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_codeflare_client.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1alpha1 "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/typed/codeflare/v1alpha1" - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" -) - -type FakeCodeflareV1alpha1 struct { - *testing.Fake -} - -func (c *FakeCodeflareV1alpha1) InstaScales(namespace string) v1alpha1.InstaScaleInterface { - return &FakeInstaScales{c, namespace} -} - -func (c *FakeCodeflareV1alpha1) MCADs(namespace string) v1alpha1.MCADInterface { - return &FakeMCADs{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeCodeflareV1alpha1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_instascale.go b/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_instascale.go deleted file mode 100644 index 8abbdc79..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_instascale.go +++ /dev/null @@ -1,189 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - json "encoding/json" - "fmt" - - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/applyconfiguration/codeflare/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeInstaScales implements InstaScaleInterface -type FakeInstaScales struct { - Fake *FakeCodeflareV1alpha1 - ns string -} - -var instascalesResource = v1alpha1.SchemeGroupVersion.WithResource("instascales") - -var instascalesKind = v1alpha1.SchemeGroupVersion.WithKind("InstaScale") - -// Get takes name of the instaScale, and returns the corresponding instaScale object, and an error if there is any. -func (c *FakeInstaScales) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.InstaScale, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(instascalesResource, c.ns, name), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} - -// List takes label and field selectors, and returns the list of InstaScales that match those selectors. -func (c *FakeInstaScales) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.InstaScaleList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(instascalesResource, instascalesKind, c.ns, opts), &v1alpha1.InstaScaleList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.InstaScaleList{ListMeta: obj.(*v1alpha1.InstaScaleList).ListMeta} - for _, item := range obj.(*v1alpha1.InstaScaleList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested instaScales. -func (c *FakeInstaScales) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(instascalesResource, c.ns, opts)) - -} - -// Create takes the representation of a instaScale and creates it. Returns the server's representation of the instaScale, and an error, if there is any. -func (c *FakeInstaScales) Create(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.CreateOptions) (result *v1alpha1.InstaScale, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(instascalesResource, c.ns, instaScale), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} - -// Update takes the representation of a instaScale and updates it. Returns the server's representation of the instaScale, and an error, if there is any. -func (c *FakeInstaScales) Update(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.UpdateOptions) (result *v1alpha1.InstaScale, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(instascalesResource, c.ns, instaScale), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeInstaScales) UpdateStatus(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.UpdateOptions) (*v1alpha1.InstaScale, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(instascalesResource, "status", c.ns, instaScale), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} - -// Delete takes name of the instaScale and deletes it. Returns an error if one occurs. -func (c *FakeInstaScales) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(instascalesResource, c.ns, name, opts), &v1alpha1.InstaScale{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeInstaScales) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(instascalesResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.InstaScaleList{}) - return err -} - -// Patch applies the patch and returns the patched instaScale. -func (c *FakeInstaScales) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.InstaScale, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(instascalesResource, c.ns, name, pt, data, subresources...), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied instaScale. -func (c *FakeInstaScales) Apply(ctx context.Context, instaScale *codeflarev1alpha1.InstaScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.InstaScale, err error) { - if instaScale == nil { - return nil, fmt.Errorf("instaScale provided to Apply must not be nil") - } - data, err := json.Marshal(instaScale) - if err != nil { - return nil, err - } - name := instaScale.Name - if name == nil { - return nil, fmt.Errorf("instaScale.Name must be provided to Apply") - } - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(instascalesResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *FakeInstaScales) ApplyStatus(ctx context.Context, instaScale *codeflarev1alpha1.InstaScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.InstaScale, err error) { - if instaScale == nil { - return nil, fmt.Errorf("instaScale provided to Apply must not be nil") - } - data, err := json.Marshal(instaScale) - if err != nil { - return nil, err - } - name := instaScale.Name - if name == nil { - return nil, fmt.Errorf("instaScale.Name must be provided to Apply") - } - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(instascalesResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1alpha1.InstaScale{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.InstaScale), err -} diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_mcad.go b/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_mcad.go deleted file mode 100644 index 027f2817..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/fake/fake_mcad.go +++ /dev/null @@ -1,189 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - json "encoding/json" - "fmt" - - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/applyconfiguration/codeflare/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeMCADs implements MCADInterface -type FakeMCADs struct { - Fake *FakeCodeflareV1alpha1 - ns string -} - -var mcadsResource = v1alpha1.SchemeGroupVersion.WithResource("mcads") - -var mcadsKind = v1alpha1.SchemeGroupVersion.WithKind("MCAD") - -// Get takes name of the mCAD, and returns the corresponding mCAD object, and an error if there is any. -func (c *FakeMCADs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MCAD, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(mcadsResource, c.ns, name), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} - -// List takes label and field selectors, and returns the list of MCADs that match those selectors. -func (c *FakeMCADs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MCADList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(mcadsResource, mcadsKind, c.ns, opts), &v1alpha1.MCADList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.MCADList{ListMeta: obj.(*v1alpha1.MCADList).ListMeta} - for _, item := range obj.(*v1alpha1.MCADList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested mCADs. -func (c *FakeMCADs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(mcadsResource, c.ns, opts)) - -} - -// Create takes the representation of a mCAD and creates it. Returns the server's representation of the mCAD, and an error, if there is any. -func (c *FakeMCADs) Create(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.CreateOptions) (result *v1alpha1.MCAD, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(mcadsResource, c.ns, mCAD), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} - -// Update takes the representation of a mCAD and updates it. Returns the server's representation of the mCAD, and an error, if there is any. -func (c *FakeMCADs) Update(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.UpdateOptions) (result *v1alpha1.MCAD, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(mcadsResource, c.ns, mCAD), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeMCADs) UpdateStatus(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.UpdateOptions) (*v1alpha1.MCAD, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(mcadsResource, "status", c.ns, mCAD), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} - -// Delete takes name of the mCAD and deletes it. Returns an error if one occurs. -func (c *FakeMCADs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(mcadsResource, c.ns, name, opts), &v1alpha1.MCAD{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeMCADs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(mcadsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.MCADList{}) - return err -} - -// Patch applies the patch and returns the patched mCAD. -func (c *FakeMCADs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MCAD, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(mcadsResource, c.ns, name, pt, data, subresources...), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied mCAD. -func (c *FakeMCADs) Apply(ctx context.Context, mCAD *codeflarev1alpha1.MCADApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MCAD, err error) { - if mCAD == nil { - return nil, fmt.Errorf("mCAD provided to Apply must not be nil") - } - data, err := json.Marshal(mCAD) - if err != nil { - return nil, err - } - name := mCAD.Name - if name == nil { - return nil, fmt.Errorf("mCAD.Name must be provided to Apply") - } - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(mcadsResource, c.ns, *name, types.ApplyPatchType, data), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *FakeMCADs) ApplyStatus(ctx context.Context, mCAD *codeflarev1alpha1.MCADApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MCAD, err error) { - if mCAD == nil { - return nil, fmt.Errorf("mCAD provided to Apply must not be nil") - } - data, err := json.Marshal(mCAD) - if err != nil { - return nil, err - } - name := mCAD.Name - if name == nil { - return nil, fmt.Errorf("mCAD.Name must be provided to Apply") - } - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(mcadsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &v1alpha1.MCAD{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.MCAD), err -} diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/instascale.go b/client/clientset/versioned/typed/codeflare/v1alpha1/instascale.go deleted file mode 100644 index c146a98d..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/instascale.go +++ /dev/null @@ -1,256 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - json "encoding/json" - "fmt" - "time" - - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/applyconfiguration/codeflare/v1alpha1" - scheme "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// InstaScalesGetter has a method to return a InstaScaleInterface. -// A group's client should implement this interface. -type InstaScalesGetter interface { - InstaScales(namespace string) InstaScaleInterface -} - -// InstaScaleInterface has methods to work with InstaScale resources. -type InstaScaleInterface interface { - Create(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.CreateOptions) (*v1alpha1.InstaScale, error) - Update(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.UpdateOptions) (*v1alpha1.InstaScale, error) - UpdateStatus(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.UpdateOptions) (*v1alpha1.InstaScale, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.InstaScale, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.InstaScaleList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.InstaScale, err error) - Apply(ctx context.Context, instaScale *codeflarev1alpha1.InstaScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.InstaScale, err error) - ApplyStatus(ctx context.Context, instaScale *codeflarev1alpha1.InstaScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.InstaScale, err error) - InstaScaleExpansion -} - -// instaScales implements InstaScaleInterface -type instaScales struct { - client rest.Interface - ns string -} - -// newInstaScales returns a InstaScales -func newInstaScales(c *CodeflareV1alpha1Client, namespace string) *instaScales { - return &instaScales{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the instaScale, and returns the corresponding instaScale object, and an error if there is any. -func (c *instaScales) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.InstaScale, err error) { - result = &v1alpha1.InstaScale{} - err = c.client.Get(). - Namespace(c.ns). - Resource("instascales"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of InstaScales that match those selectors. -func (c *instaScales) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.InstaScaleList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.InstaScaleList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("instascales"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested instaScales. -func (c *instaScales) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("instascales"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a instaScale and creates it. Returns the server's representation of the instaScale, and an error, if there is any. -func (c *instaScales) Create(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.CreateOptions) (result *v1alpha1.InstaScale, err error) { - result = &v1alpha1.InstaScale{} - err = c.client.Post(). - Namespace(c.ns). - Resource("instascales"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(instaScale). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a instaScale and updates it. Returns the server's representation of the instaScale, and an error, if there is any. -func (c *instaScales) Update(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.UpdateOptions) (result *v1alpha1.InstaScale, err error) { - result = &v1alpha1.InstaScale{} - err = c.client.Put(). - Namespace(c.ns). - Resource("instascales"). - Name(instaScale.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(instaScale). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *instaScales) UpdateStatus(ctx context.Context, instaScale *v1alpha1.InstaScale, opts v1.UpdateOptions) (result *v1alpha1.InstaScale, err error) { - result = &v1alpha1.InstaScale{} - err = c.client.Put(). - Namespace(c.ns). - Resource("instascales"). - Name(instaScale.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(instaScale). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the instaScale and deletes it. Returns an error if one occurs. -func (c *instaScales) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("instascales"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *instaScales) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("instascales"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched instaScale. -func (c *instaScales) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.InstaScale, err error) { - result = &v1alpha1.InstaScale{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("instascales"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied instaScale. -func (c *instaScales) Apply(ctx context.Context, instaScale *codeflarev1alpha1.InstaScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.InstaScale, err error) { - if instaScale == nil { - return nil, fmt.Errorf("instaScale provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(instaScale) - if err != nil { - return nil, err - } - name := instaScale.Name - if name == nil { - return nil, fmt.Errorf("instaScale.Name must be provided to Apply") - } - result = &v1alpha1.InstaScale{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("instascales"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *instaScales) ApplyStatus(ctx context.Context, instaScale *codeflarev1alpha1.InstaScaleApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.InstaScale, err error) { - if instaScale == nil { - return nil, fmt.Errorf("instaScale provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(instaScale) - if err != nil { - return nil, err - } - - name := instaScale.Name - if name == nil { - return nil, fmt.Errorf("instaScale.Name must be provided to Apply") - } - - result = &v1alpha1.InstaScale{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("instascales"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/mcad.go b/client/clientset/versioned/typed/codeflare/v1alpha1/mcad.go deleted file mode 100644 index 7d70e403..00000000 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/mcad.go +++ /dev/null @@ -1,256 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - json "encoding/json" - "fmt" - "time" - - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/client/applyconfiguration/codeflare/v1alpha1" - scheme "github.com/project-codeflare/codeflare-operator/client/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// MCADsGetter has a method to return a MCADInterface. -// A group's client should implement this interface. -type MCADsGetter interface { - MCADs(namespace string) MCADInterface -} - -// MCADInterface has methods to work with MCAD resources. -type MCADInterface interface { - Create(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.CreateOptions) (*v1alpha1.MCAD, error) - Update(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.UpdateOptions) (*v1alpha1.MCAD, error) - UpdateStatus(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.UpdateOptions) (*v1alpha1.MCAD, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.MCAD, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.MCADList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MCAD, err error) - Apply(ctx context.Context, mCAD *codeflarev1alpha1.MCADApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MCAD, err error) - ApplyStatus(ctx context.Context, mCAD *codeflarev1alpha1.MCADApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MCAD, err error) - MCADExpansion -} - -// mCADs implements MCADInterface -type mCADs struct { - client rest.Interface - ns string -} - -// newMCADs returns a MCADs -func newMCADs(c *CodeflareV1alpha1Client, namespace string) *mCADs { - return &mCADs{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the mCAD, and returns the corresponding mCAD object, and an error if there is any. -func (c *mCADs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.MCAD, err error) { - result = &v1alpha1.MCAD{} - err = c.client.Get(). - Namespace(c.ns). - Resource("mcads"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of MCADs that match those selectors. -func (c *mCADs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.MCADList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.MCADList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("mcads"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested mCADs. -func (c *mCADs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("mcads"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a mCAD and creates it. Returns the server's representation of the mCAD, and an error, if there is any. -func (c *mCADs) Create(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.CreateOptions) (result *v1alpha1.MCAD, err error) { - result = &v1alpha1.MCAD{} - err = c.client.Post(). - Namespace(c.ns). - Resource("mcads"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(mCAD). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a mCAD and updates it. Returns the server's representation of the mCAD, and an error, if there is any. -func (c *mCADs) Update(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.UpdateOptions) (result *v1alpha1.MCAD, err error) { - result = &v1alpha1.MCAD{} - err = c.client.Put(). - Namespace(c.ns). - Resource("mcads"). - Name(mCAD.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(mCAD). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *mCADs) UpdateStatus(ctx context.Context, mCAD *v1alpha1.MCAD, opts v1.UpdateOptions) (result *v1alpha1.MCAD, err error) { - result = &v1alpha1.MCAD{} - err = c.client.Put(). - Namespace(c.ns). - Resource("mcads"). - Name(mCAD.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(mCAD). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the mCAD and deletes it. Returns an error if one occurs. -func (c *mCADs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("mcads"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *mCADs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("mcads"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched mCAD. -func (c *mCADs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.MCAD, err error) { - result = &v1alpha1.MCAD{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("mcads"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// Apply takes the given apply declarative configuration, applies it and returns the applied mCAD. -func (c *mCADs) Apply(ctx context.Context, mCAD *codeflarev1alpha1.MCADApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MCAD, err error) { - if mCAD == nil { - return nil, fmt.Errorf("mCAD provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(mCAD) - if err != nil { - return nil, err - } - name := mCAD.Name - if name == nil { - return nil, fmt.Errorf("mCAD.Name must be provided to Apply") - } - result = &v1alpha1.MCAD{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("mcads"). - Name(*name). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} - -// ApplyStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). -func (c *mCADs) ApplyStatus(ctx context.Context, mCAD *codeflarev1alpha1.MCADApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.MCAD, err error) { - if mCAD == nil { - return nil, fmt.Errorf("mCAD provided to Apply must not be nil") - } - patchOpts := opts.ToPatchOptions() - data, err := json.Marshal(mCAD) - if err != nil { - return nil, err - } - - name := mCAD.Name - if name == nil { - return nil, fmt.Errorf("mCAD.Name must be provided to Apply") - } - - result = &v1alpha1.MCAD{} - err = c.client.Patch(types.ApplyPatchType). - Namespace(c.ns). - Resource("mcads"). - Name(*name). - SubResource("status"). - VersionedParams(&patchOpts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/client/informer/externalversions/codeflare/interface.go b/client/informer/externalversions/codeflare/interface.go deleted file mode 100644 index 63ab10ff..00000000 --- a/client/informer/externalversions/codeflare/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package codeflare - -import ( - v1alpha1 "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/codeflare/v1alpha1" - internalinterfaces "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1alpha1 provides access to shared informers for resources in V1alpha1. - V1alpha1() v1alpha1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1alpha1 returns a new v1alpha1.Interface. -func (g *group) V1alpha1() v1alpha1.Interface { - return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/client/informer/externalversions/codeflare/v1alpha1/instascale.go b/client/informer/externalversions/codeflare/v1alpha1/instascale.go deleted file mode 100644 index 70346e65..00000000 --- a/client/informer/externalversions/codeflare/v1alpha1/instascale.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - time "time" - - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - versioned "github.com/project-codeflare/codeflare-operator/client/clientset/versioned" - internalinterfaces "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/internalinterfaces" - v1alpha1 "github.com/project-codeflare/codeflare-operator/client/listers/codeflare/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// InstaScaleInformer provides access to a shared informer and lister for -// InstaScales. -type InstaScaleInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.InstaScaleLister -} - -type instaScaleInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewInstaScaleInformer constructs a new informer for InstaScale type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewInstaScaleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredInstaScaleInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredInstaScaleInformer constructs a new informer for InstaScale type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredInstaScaleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.CodeflareV1alpha1().InstaScales(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.CodeflareV1alpha1().InstaScales(namespace).Watch(context.TODO(), options) - }, - }, - &codeflarev1alpha1.InstaScale{}, - resyncPeriod, - indexers, - ) -} - -func (f *instaScaleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredInstaScaleInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *instaScaleInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&codeflarev1alpha1.InstaScale{}, f.defaultInformer) -} - -func (f *instaScaleInformer) Lister() v1alpha1.InstaScaleLister { - return v1alpha1.NewInstaScaleLister(f.Informer().GetIndexer()) -} diff --git a/client/informer/externalversions/codeflare/v1alpha1/interface.go b/client/informer/externalversions/codeflare/v1alpha1/interface.go deleted file mode 100644 index 6003a703..00000000 --- a/client/informer/externalversions/codeflare/v1alpha1/interface.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - internalinterfaces "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // InstaScales returns a InstaScaleInformer. - InstaScales() InstaScaleInformer - // MCADs returns a MCADInformer. - MCADs() MCADInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// InstaScales returns a InstaScaleInformer. -func (v *version) InstaScales() InstaScaleInformer { - return &instaScaleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - -// MCADs returns a MCADInformer. -func (v *version) MCADs() MCADInformer { - return &mCADInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/client/informer/externalversions/codeflare/v1alpha1/mcad.go b/client/informer/externalversions/codeflare/v1alpha1/mcad.go deleted file mode 100644 index 2fe4d5a3..00000000 --- a/client/informer/externalversions/codeflare/v1alpha1/mcad.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - time "time" - - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - versioned "github.com/project-codeflare/codeflare-operator/client/clientset/versioned" - internalinterfaces "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/internalinterfaces" - v1alpha1 "github.com/project-codeflare/codeflare-operator/client/listers/codeflare/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// MCADInformer provides access to a shared informer and lister for -// MCADs. -type MCADInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.MCADLister -} - -type mCADInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewMCADInformer constructs a new informer for MCAD type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewMCADInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredMCADInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredMCADInformer constructs a new informer for MCAD type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredMCADInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.CodeflareV1alpha1().MCADs(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.CodeflareV1alpha1().MCADs(namespace).Watch(context.TODO(), options) - }, - }, - &codeflarev1alpha1.MCAD{}, - resyncPeriod, - indexers, - ) -} - -func (f *mCADInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredMCADInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *mCADInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&codeflarev1alpha1.MCAD{}, f.defaultInformer) -} - -func (f *mCADInformer) Lister() v1alpha1.MCADLister { - return v1alpha1.NewMCADLister(f.Informer().GetIndexer()) -} diff --git a/client/informer/externalversions/factory.go b/client/informer/externalversions/factory.go deleted file mode 100644 index e1f7f14a..00000000 --- a/client/informer/externalversions/factory.go +++ /dev/null @@ -1,251 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - reflect "reflect" - sync "sync" - time "time" - - versioned "github.com/project-codeflare/codeflare-operator/client/clientset/versioned" - codeflare "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/codeflare" - internalinterfaces "github.com/project-codeflare/codeflare-operator/client/informer/externalversions/internalinterfaces" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" -) - -// SharedInformerOption defines the functional option type for SharedInformerFactory. -type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory - -type sharedInformerFactory struct { - client versioned.Interface - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc - lock sync.Mutex - defaultResync time.Duration - customResync map[reflect.Type]time.Duration - - informers map[reflect.Type]cache.SharedIndexInformer - // startedInformers is used for tracking which informers have been started. - // This allows Start() to be called multiple times safely. - startedInformers map[reflect.Type]bool - // wg tracks how many goroutines were started. - wg sync.WaitGroup - // shuttingDown is true when Shutdown has been called. It may still be running - // because it needs to wait for goroutines. - shuttingDown bool -} - -// WithCustomResyncConfig sets a custom resync period for the specified informer types. -func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - for k, v := range resyncConfig { - factory.customResync[reflect.TypeOf(k)] = v - } - return factory - } -} - -// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. -func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.tweakListOptions = tweakListOptions - return factory - } -} - -// WithNamespace limits the SharedInformerFactory to the specified namespace. -func WithNamespace(namespace string) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.namespace = namespace - return factory - } -} - -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. -func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync) -} - -// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. -// Listers obtained via this SharedInformerFactory will be subject to the same filters -// as specified here. -// Deprecated: Please use NewSharedInformerFactoryWithOptions instead -func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) -} - -// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. -func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { - factory := &sharedInformerFactory{ - client: client, - namespace: v1.NamespaceAll, - defaultResync: defaultResync, - informers: make(map[reflect.Type]cache.SharedIndexInformer), - startedInformers: make(map[reflect.Type]bool), - customResync: make(map[reflect.Type]time.Duration), - } - - // Apply all options - for _, opt := range options { - factory = opt(factory) - } - - return factory -} - -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - if f.shuttingDown { - return - } - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - f.wg.Add(1) - // We need a new variable in each loop iteration, - // otherwise the goroutine would use the loop variable - // and that keeps changing. - informer := informer - go func() { - defer f.wg.Done() - informer.Run(stopCh) - }() - f.startedInformers[informerType] = true - } - } -} - -func (f *sharedInformerFactory) Shutdown() { - f.lock.Lock() - f.shuttingDown = true - f.lock.Unlock() - - // Will return immediately if there is nothing to wait for. - f.wg.Wait() -} - -func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { - informers := func() map[reflect.Type]cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informers := map[reflect.Type]cache.SharedIndexInformer{} - for informerType, informer := range f.informers { - if f.startedInformers[informerType] { - informers[informerType] = informer - } - } - return informers - }() - - res := map[reflect.Type]bool{} - for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) - } - return res -} - -// InternalInformerFor returns the SharedIndexInformer for obj using an internal -// client. -func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informerType := reflect.TypeOf(obj) - informer, exists := f.informers[informerType] - if exists { - return informer - } - - resyncPeriod, exists := f.customResync[informerType] - if !exists { - resyncPeriod = f.defaultResync - } - - informer = newFunc(f.client, resyncPeriod) - f.informers[informerType] = informer - - return informer -} - -// SharedInformerFactory provides shared informers for resources in all known -// API group versions. -// -// It is typically used like this: -// -// ctx, cancel := context.Background() -// defer cancel() -// factory := NewSharedInformerFactory(client, resyncPeriod) -// defer factory.WaitForStop() // Returns immediately if nothing was started. -// genericInformer := factory.ForResource(resource) -// typedInformer := factory.SomeAPIGroup().V1().SomeType() -// factory.Start(ctx.Done()) // Start processing these informers. -// synced := factory.WaitForCacheSync(ctx.Done()) -// for v, ok := range synced { -// if !ok { -// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) -// return -// } -// } -// -// // Creating informers can also be created after Start, but then -// // Start must be called again: -// anotherGenericInformer := factory.ForResource(resource) -// factory.Start(ctx.Done()) -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - - // Start initializes all requested informers. They are handled in goroutines - // which run until the stop channel gets closed. - Start(stopCh <-chan struct{}) - - // Shutdown marks a factory as shutting down. At that point no new - // informers can be started anymore and Start will return without - // doing anything. - // - // In addition, Shutdown blocks until all goroutines have terminated. For that - // to happen, the close channel(s) that they were started with must be closed, - // either before Shutdown gets called or while it is waiting. - // - // Shutdown may be called multiple times, even concurrently. All such calls will - // block until all goroutines have terminated. - Shutdown() - - // WaitForCacheSync blocks until all started informers' caches were synced - // or the stop channel gets closed. - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - // ForResource gives generic access to a shared informer of the matching type. - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - - // InternalInformerFor returns the SharedIndexInformer for obj using an internal - // client. - InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer - - Codeflare() codeflare.Interface -} - -func (f *sharedInformerFactory) Codeflare() codeflare.Interface { - return codeflare.New(f, f.namespace, f.tweakListOptions) -} diff --git a/client/informer/externalversions/generic.go b/client/informer/externalversions/generic.go deleted file mode 100644 index 9eea54eb..00000000 --- a/client/informer/externalversions/generic.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - "fmt" - - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" -) - -// GenericInformer is type of SharedIndexInformer which will locate and delegate to other -// sharedInformers based on type -type GenericInformer interface { - Informer() cache.SharedIndexInformer - Lister() cache.GenericLister -} - -type genericInformer struct { - informer cache.SharedIndexInformer - resource schema.GroupResource -} - -// Informer returns the SharedIndexInformer. -func (f *genericInformer) Informer() cache.SharedIndexInformer { - return f.informer -} - -// Lister returns the GenericLister. -func (f *genericInformer) Lister() cache.GenericLister { - return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) -} - -// ForResource gives generic access to a shared informer of the matching type -// TODO extend this to unknown resources with a client pool -func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { - switch resource { - // Group=codeflare.codeflare.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("instascales"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Codeflare().V1alpha1().InstaScales().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("mcads"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Codeflare().V1alpha1().MCADs().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/client/informer/externalversions/internalinterfaces/factory_interfaces.go b/client/informer/externalversions/internalinterfaces/factory_interfaces.go deleted file mode 100644 index b380f668..00000000 --- a/client/informer/externalversions/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalinterfaces - -import ( - time "time" - - versioned "github.com/project-codeflare/codeflare-operator/client/clientset/versioned" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" -) - -// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. -type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer - -// SharedInformerFactory a small interface to allow for adding an informer without an import cycle -type SharedInformerFactory interface { - Start(stopCh <-chan struct{}) - InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer -} - -// TweakListOptionsFunc is a function that transforms a v1.ListOptions. -type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/client/listers/codeflare/v1alpha1/expansion_generated.go b/client/listers/codeflare/v1alpha1/expansion_generated.go deleted file mode 100644 index 23082ab9..00000000 --- a/client/listers/codeflare/v1alpha1/expansion_generated.go +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -// InstaScaleListerExpansion allows custom methods to be added to -// InstaScaleLister. -type InstaScaleListerExpansion interface{} - -// InstaScaleNamespaceListerExpansion allows custom methods to be added to -// InstaScaleNamespaceLister. -type InstaScaleNamespaceListerExpansion interface{} - -// MCADListerExpansion allows custom methods to be added to -// MCADLister. -type MCADListerExpansion interface{} - -// MCADNamespaceListerExpansion allows custom methods to be added to -// MCADNamespaceLister. -type MCADNamespaceListerExpansion interface{} diff --git a/client/listers/codeflare/v1alpha1/instascale.go b/client/listers/codeflare/v1alpha1/instascale.go deleted file mode 100644 index ee5c2284..00000000 --- a/client/listers/codeflare/v1alpha1/instascale.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// InstaScaleLister helps list InstaScales. -// All objects returned here must be treated as read-only. -type InstaScaleLister interface { - // List lists all InstaScales in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.InstaScale, err error) - // InstaScales returns an object that can list and get InstaScales. - InstaScales(namespace string) InstaScaleNamespaceLister - InstaScaleListerExpansion -} - -// instaScaleLister implements the InstaScaleLister interface. -type instaScaleLister struct { - indexer cache.Indexer -} - -// NewInstaScaleLister returns a new InstaScaleLister. -func NewInstaScaleLister(indexer cache.Indexer) InstaScaleLister { - return &instaScaleLister{indexer: indexer} -} - -// List lists all InstaScales in the indexer. -func (s *instaScaleLister) List(selector labels.Selector) (ret []*v1alpha1.InstaScale, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.InstaScale)) - }) - return ret, err -} - -// InstaScales returns an object that can list and get InstaScales. -func (s *instaScaleLister) InstaScales(namespace string) InstaScaleNamespaceLister { - return instaScaleNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// InstaScaleNamespaceLister helps list and get InstaScales. -// All objects returned here must be treated as read-only. -type InstaScaleNamespaceLister interface { - // List lists all InstaScales in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.InstaScale, err error) - // Get retrieves the InstaScale from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.InstaScale, error) - InstaScaleNamespaceListerExpansion -} - -// instaScaleNamespaceLister implements the InstaScaleNamespaceLister -// interface. -type instaScaleNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all InstaScales in the indexer for a given namespace. -func (s instaScaleNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.InstaScale, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.InstaScale)) - }) - return ret, err -} - -// Get retrieves the InstaScale from the indexer for a given namespace and name. -func (s instaScaleNamespaceLister) Get(name string) (*v1alpha1.InstaScale, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("instascale"), name) - } - return obj.(*v1alpha1.InstaScale), nil -} diff --git a/client/listers/codeflare/v1alpha1/mcad.go b/client/listers/codeflare/v1alpha1/mcad.go deleted file mode 100644 index 8ac44bfc..00000000 --- a/client/listers/codeflare/v1alpha1/mcad.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// MCADLister helps list MCADs. -// All objects returned here must be treated as read-only. -type MCADLister interface { - // List lists all MCADs in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.MCAD, err error) - // MCADs returns an object that can list and get MCADs. - MCADs(namespace string) MCADNamespaceLister - MCADListerExpansion -} - -// mCADLister implements the MCADLister interface. -type mCADLister struct { - indexer cache.Indexer -} - -// NewMCADLister returns a new MCADLister. -func NewMCADLister(indexer cache.Indexer) MCADLister { - return &mCADLister{indexer: indexer} -} - -// List lists all MCADs in the indexer. -func (s *mCADLister) List(selector labels.Selector) (ret []*v1alpha1.MCAD, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.MCAD)) - }) - return ret, err -} - -// MCADs returns an object that can list and get MCADs. -func (s *mCADLister) MCADs(namespace string) MCADNamespaceLister { - return mCADNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// MCADNamespaceLister helps list and get MCADs. -// All objects returned here must be treated as read-only. -type MCADNamespaceLister interface { - // List lists all MCADs in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.MCAD, err error) - // Get retrieves the MCAD from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.MCAD, error) - MCADNamespaceListerExpansion -} - -// mCADNamespaceLister implements the MCADNamespaceLister -// interface. -type mCADNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all MCADs in the indexer for a given namespace. -func (s mCADNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.MCAD, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.MCAD)) - }) - return ret, err -} - -// Get retrieves the MCAD from the indexer for a given namespace and name. -func (s mCADNamespaceLister) Get(name string) (*v1alpha1.MCAD, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("mcad"), name) - } - return obj.(*v1alpha1.MCAD), nil -} diff --git a/config/crd/bases/codeflare.codeflare.dev_instascales.yaml b/config/crd/bases/codeflare.codeflare.dev_instascales.yaml deleted file mode 100644 index 26a72b76..00000000 --- a/config/crd/bases/codeflare.codeflare.dev_instascales.yaml +++ /dev/null @@ -1,126 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: instascales.codeflare.codeflare.dev -spec: - group: codeflare.codeflare.dev - names: - kind: InstaScale - listKind: InstaScaleList - plural: instascales - singular: instascale - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: InstaScale is the Schema for the instascales 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: InstaScaleSpec defines the desired state of InstaScale - properties: - controllerImage: - description: The container image for the InstaScale controller deployment. - If specified, the provided container image must be compatible with - the running CodeFlare operator. Using an incompatible, or unrelated - container image, will result in an undefined behavior. A CodeFlare - operator upgrade will not upgrade the InstaScale controller, that'll - keep running this specified container image. If not specified, the - latest version compatible with the running CodeFlare operator is - used. A CodeFlare operator upgrade may upgrade the InstaScale controller - to a newer container image. - type: string - controllerResources: - description: controllerResources determines the container resources - for the InstaScale controller deployment - properties: - claims: - description: "Claims lists the names of resources, defined in - spec.resourceClaims, that are used by this container. \n This - is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be set - for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in pod.spec.resourceClaims - of the Pod where this field is used. It makes that resource - available inside a container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute resources - allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - enableMonitoring: - default: true - description: enableMonitoring determines if monitoring artifacts are - deployed for the InstaScale instance. - type: boolean - maxScaleoutAllowed: - default: 15 - description: maxScaleoutAllowed determines the max number of machines - that can be scaled up by InstaScale - type: integer - useMachinePools: - default: false - description: useMachinePools determines whether InstaScale should - use MachineSets or MachinePools for scaling - type: boolean - type: object - status: - description: InstaScaleStatus defines the observed state of InstaScale - properties: - ready: - default: false - type: boolean - required: - - ready - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/bases/codeflare.codeflare.dev_mcads.yaml b/config/crd/bases/codeflare.codeflare.dev_mcads.yaml deleted file mode 100644 index 8172df33..00000000 --- a/config/crd/bases/codeflare.codeflare.dev_mcads.yaml +++ /dev/null @@ -1,144 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: mcads.codeflare.codeflare.dev -spec: - group: codeflare.codeflare.dev - names: - kind: MCAD - listKind: MCADList - plural: mcads - singular: mcad - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: MCAD is the Schema for the mcads 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: MCADSpec defines the desired state of MCAD - properties: - agentConfigs: - description: AgentConfigs determine paths to agent config file:deploymentName - separated by commas(,). - type: string - controllerImage: - description: The container image for the MCAD controller deployment. - If specified, the provided container image must be compatible with - the running CodeFlare operator. Using an incompatible, or unrelated - container image, will result in an undefined behavior. A CodeFlare - operator upgrade will not upgrade the MCAD controller, that'll keep - running this specified container image. If not specified, the latest - version compatible with the running CodeFlare operator is used. - A CodeFlare operator upgrade may upgrade the MCAD controller to - a newer container image. - type: string - controllerResources: - description: ControllerResources defines the cpu and memory resource - requirements for the MCAD Controller - properties: - claims: - description: "Claims lists the names of resources, defined in - spec.resourceClaims, that are used by this container. \n This - is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be set - for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in pod.spec.resourceClaims - of the Pod where this field is used. It makes that resource - available inside a container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute resources - allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' - type: object - type: object - dispatcherMode: - default: false - description: DispatcherMode determines whether the MCAD Controller - should be launched in Dispatcher mode. - type: boolean - enableMonitoring: - default: true - description: EnableMonitoring determines if monitoring artifacts are - deployed for the MCAD instance. - type: boolean - multiCluster: - default: false - description: MultiCluster determines if MCAD will be routing traffic - to multiple clusters. - type: boolean - podCreationTimeout: - default: -1 - description: PodCreationTimeout determines timeout in milliseconds - for pods to be created after dispatching job. - type: integer - preemptionEnabled: - default: false - description: PreemptionEnabled determines if scheduled jobs can be - preempted for others - type: boolean - quotaRestURL: - description: QuotaRestURL determines URL for Rest quota management. - type: string - type: object - status: - description: MCADStatus defines the observed state of MCAD - properties: - ready: - description: Ready indicates whether the application is ready to serve - requests - type: boolean - required: - - ready - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml deleted file mode 100644 index 725db012..00000000 --- a/config/crd/kustomization.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# 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/codeflare.codeflare.dev_mcads.yaml -- bases/codeflare.codeflare.dev_instascales.yaml -- mcad -#+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_mcads.yaml -#- patches/webhook_in_instascales.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_mcads.yaml -#- patches/cainjection_in_instascales.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch - -# the following config is for teaching kustomize how to do kustomization for CRDs. -configurations: -- kustomizeconfig.yaml diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml deleted file mode 100644 index ec5c150a..00000000 --- a/config/crd/kustomizeconfig.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# This file is for teaching kustomize how to substitute name and namespace reference in CRD -nameReference: -- kind: Service - version: v1 - fieldSpecs: - - kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/name - -namespace: -- kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/namespace - create: false - -varReference: -- path: metadata/annotations diff --git a/config/crd/mcad/kustomization.yaml b/config/crd/mcad/kustomization.yaml deleted file mode 100644 index a433f833..00000000 --- a/config/crd/mcad/kustomization.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- github.com/project-codeflare/multi-cluster-app-dispatcher/config/crd?ref=release-v0.0.0 # kpt-set: ${MCAD_CRD} diff --git a/config/crd/patches/cainjection_in_instascales.yaml b/config/crd/patches/cainjection_in_instascales.yaml deleted file mode 100644 index 12b00004..00000000 --- a/config/crd/patches/cainjection_in_instascales.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: instascales.codeflare.codeflare.dev diff --git a/config/crd/patches/cainjection_in_mcads.yaml b/config/crd/patches/cainjection_in_mcads.yaml deleted file mode 100644 index ddaad38d..00000000 --- a/config/crd/patches/cainjection_in_mcads.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: mcads.codeflare.codeflare.dev diff --git a/config/crd/patches/webhook_in_instascales.yaml b/config/crd/patches/webhook_in_instascales.yaml deleted file mode 100644 index 55d5cf2b..00000000 --- a/config/crd/patches/webhook_in_instascales.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: instascales.codeflare.codeflare.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/crd/patches/webhook_in_mcads.yaml b/config/crd/patches/webhook_in_mcads.yaml deleted file mode 100644 index ca858acf..00000000 --- a/config/crd/patches/webhook_in_mcads.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# The following patch enables a conversion webhook for the CRD -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: mcads.codeflare.codeflare.dev -spec: - conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 1bfe8c54..71d9fd58 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -1,5 +1,5 @@ # Adds namespace to all resources. -namespace: openshift-operators +namespace: opendatahub # Value of this field is prepended to the # names of all resources, e.g. a deployment named @@ -14,62 +14,14 @@ commonLabels: app.kubernetes.io/part-of: codeflare 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 + - ../rbac + - ../manager + - ../webhook # [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 +resources: + - metrics_service.yaml -# Mount the controller config file for loading manager configurations -# through a ComponentConfig type -# - manager_config_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: -# [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: v1 -# 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: v1 -# 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 +patches: + - path: manager_webhook_patch.yaml diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml deleted file mode 100644 index 24d5b119..00000000 --- a/config/default/manager_auth_proxy_patch.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# 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: manager - namespace: system -spec: - template: - spec: - containers: - - name: kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" - - "--logtostderr=true" - - "--v=0" - ports: - - containerPort: 8443 - protocol: TCP - name: https - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 5m - memory: 64Mi - - name: manager - args: - - "--health-probe-bind-address=:8081" - - "--metrics-bind-address=127.0.0.1:8080" - - "--leader-elect" diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml deleted file mode 100644 index 98456c9a..00000000 --- a/config/default/manager_config_patch.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: manager - namespace: system -spec: - template: - spec: - containers: - - name: manager - args: - - "--config=controller_manager_config.yaml" - volumeMounts: - - name: manager-config - mountPath: /controller_manager_config.yaml - subPath: controller_manager_config.yaml - volumes: - - name: manager-config - configMap: - name: manager-config diff --git a/config/default/manager_webhook_patch.yaml b/config/default/manager_webhook_patch.yaml new file mode 100644 index 00000000..ab553c00 --- /dev/null +++ b/config/default/manager_webhook_patch.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: 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 diff --git a/config/rbac/auth_proxy_service.yaml b/config/default/metrics_service.yaml similarity index 79% rename from config/rbac/auth_proxy_service.yaml rename to config/default/metrics_service.yaml index 25010042..0f420610 100644 --- a/config/rbac/auth_proxy_service.yaml +++ b/config/default/metrics_service.yaml @@ -5,10 +5,10 @@ metadata: namespace: system spec: ports: - - name: https - port: 8443 + - name: metrics + port: 8080 protocol: TCP - targetPort: https + targetPort: metrics selector: app.kubernetes.io/name: codeflare-operator app.kubernetes.io/part-of: codeflare diff --git a/config/e2e/config.yaml b/config/e2e/config.yaml new file mode 100644 index 00000000..6b8f55a0 --- /dev/null +++ b/config/e2e/config.yaml @@ -0,0 +1,9 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: codeflare-operator-config +data: + config.yaml: | + kuberay: + rayDashboardOAuthEnabled: false + ingressDomain: "kind" diff --git a/config/e2e/kustomization.yaml b/config/e2e/kustomization.yaml new file mode 100644 index 00000000..772370da --- /dev/null +++ b/config/e2e/kustomization.yaml @@ -0,0 +1,12 @@ +namespace: openshift-operators + +bases: +- config.yaml +- ../default + +patches: + - target: + kind: Deployment + name: manager + namespace: system + path: patch_resources.yaml diff --git a/config/e2e/patch_resources.yaml b/config/e2e/patch_resources.yaml new file mode 100644 index 00000000..3da1d5f3 --- /dev/null +++ b/config/e2e/patch_resources.yaml @@ -0,0 +1,2 @@ +- op: remove + path: /spec/template/spec/containers/0/resources diff --git a/config/internal/instascale/clusterrole.yaml.tmpl b/config/internal/instascale/clusterrole.yaml.tmpl deleted file mode 100644 index 8f27f57f..00000000 --- a/config/internal/instascale/clusterrole.yaml.tmpl +++ /dev/null @@ -1,73 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: instascale-{{.Name}}-cr - labels: - app.kubernetes.io/managed-by: InstaScale - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -rules: -- apiGroups: - - "" - resources: - - nodes - - configmaps - verbs: - - list - - watch - - get - - create - - update - - delete - - patch - -- apiGroups: - - "" - resourceNames: - - instascale-ocm-secret - resources: - - secrets - verbs: - - get - -- apiGroups: - - config.openshift.io - resources: - - clusterversions - verbs: - - get - - list - -- apiGroups: - - apps - resources: - - deployments - verbs: - - list - - watch - - get -- apiGroups: - - machine.openshift.io - resources: - - "*" - verbs: - - list - - watch - - get - - create - - update - - delete - - patch - -- apiGroups: - - mcad.ibm.com - resources: - - appwrappers - verbs: - - list - - watch - - get - - create - - update - - delete - - patch diff --git a/config/internal/instascale/clusterrolebinding.yaml.tmpl b/config/internal/instascale/clusterrolebinding.yaml.tmpl deleted file mode 100644 index ef775b42..00000000 --- a/config/internal/instascale/clusterrolebinding.yaml.tmpl +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: instascale-{{.Name}}-crb - labels: - app.kubernetes.io/managed-by: InstaScale - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: instascale-{{.Name}}-cr -subjects: -- kind: ServiceAccount - name: instascale-{{.Name}}-sa - namespace: {{.Namespace}} diff --git a/config/internal/instascale/configmap.yaml.tmpl b/config/internal/instascale/configmap.yaml.tmpl deleted file mode 100644 index 8e665ecc..00000000 --- a/config/internal/instascale/configmap.yaml.tmpl +++ /dev/null @@ -1,11 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: instascale-config - namespace: {{.Namespace}} - labels: - app: instascale-{{.Name}} - component: instascale -data: - maxScaleoutAllowed: "{{.MaxScaleoutAllowed}}" - useMachinePools: "{{.UseMachinePools}}" diff --git a/config/internal/instascale/deployment.yaml.tmpl b/config/internal/instascale/deployment.yaml.tmpl deleted file mode 100644 index fe21ade6..00000000 --- a/config/internal/instascale/deployment.yaml.tmpl +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: instascale-{{.Name}} - name: instascale-{{.Name}} - namespace: {{.Namespace}} -spec: - replicas: 1 - selector: - matchLabels: - app: instascale-{{.Name}} - template: - metadata: - labels: - app: instascale-{{.Name}} - spec: - containers: - - args: - - "--configs-namespace={{.Namespace}}" - image: {{.ControllerImage}} - name: instascale - resources: {{.ControllerResources}} - livenessProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 5 - timeoutSeconds: 5 - readinessProbe: - httpGet: - path: /readyz - port: 8081 - periodSeconds: 10 - serviceAccountName: instascale-{{.Name}}-sa diff --git a/config/internal/instascale/sa.yaml.tmpl b/config/internal/instascale/sa.yaml.tmpl deleted file mode 100644 index 562265ac..00000000 --- a/config/internal/instascale/sa.yaml.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: instascale-{{.Name}}-sa - namespace: {{.Namespace}} diff --git a/config/internal/mcad/apiservice_custom-metrics.yaml b/config/internal/mcad/apiservice_custom-metrics.yaml deleted file mode 100644 index b054fee1..00000000 --- a/config/internal/mcad/apiservice_custom-metrics.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# {{ if (eq .Values.configMap.multiCluster true) }} -apiVersion: apiregistration.k8s.io/v1beta1 -kind: APIService -metadata: - name: v1beta1.custom.metrics.k8s.io - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -spec: - service: - name: mcad-{{.Name}}-metrics - namespace: {{.Namespace}} - group: custom.metrics.k8s.io - version: v1beta1 - insecureSkipTLSVerify: true - groupPriorityMinimum: 100 - versionPriority: 100 diff --git a/config/internal/mcad/apiservice_external-metrics.yaml b/config/internal/mcad/apiservice_external-metrics.yaml deleted file mode 100644 index 0c242c11..00000000 --- a/config/internal/mcad/apiservice_external-metrics.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# {{ if (eq .Values.configMap.multiCluster true) }} -apiVersion: apiregistration.k8s.io/v1beta1 -kind: APIService -metadata: - name: v1beta1.external.metrics.k8s.io - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -spec: - service: - name: mcad-{{.Name}}-metrics - namespace: {{.Namespace}} - group: external.metrics.k8s.io - version: v1beta1 - insecureSkipTLSVerify: true - groupPriorityMinimum: 100 - versionPriority: 100 diff --git a/config/internal/mcad/clusterrole_custom-metrics-server-admin.yaml.tmpl b/config/internal/mcad/clusterrole_custom-metrics-server-admin.yaml.tmpl deleted file mode 100644 index e7500795..00000000 --- a/config/internal/mcad/clusterrole_custom-metrics-server-admin.yaml.tmpl +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{.Name}}-mcad-custom-metrics-server-admin-role - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -rules: - - apiGroups: - - custom.metrics.k8s.io - resources: ["*"] - verbs: ["*"] diff --git a/config/internal/mcad/clusterrole_mcad-controller.yaml.tmpl b/config/internal/mcad/clusterrole_mcad-controller.yaml.tmpl deleted file mode 100644 index 7d49f5fe..00000000 --- a/config/internal/mcad/clusterrole_mcad-controller.yaml.tmpl +++ /dev/null @@ -1,56 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: {{.Name}}-mcad-controller-role - labels: - kubernetes.io/bootstrapping: rbac-defaults - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -rules: - - apiGroups: - - mcad.ibm.com - resources: - - queuejobs - - schedulingspecs - - appwrappers - - appwrappers/finalizers - - appwrappers/status - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - persistentvolumes - - namespaces - - lists - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - scheduling.sigs.k8s.io - resources: - - podgroups - verbs: - - get - - list - - watch - - create - - update - - patch - - delete diff --git a/config/internal/mcad/clusterrole_metrics-resource-reader.yaml.tmpl b/config/internal/mcad/clusterrole_metrics-resource-reader.yaml.tmpl deleted file mode 100644 index 99f12b69..00000000 --- a/config/internal/mcad/clusterrole_metrics-resource-reader.yaml.tmpl +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{.Name}}-mcad-metrics-resource-reader-role - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -rules: - - apiGroups: - - "" - resources: - - namespaces - - pods - - services - verbs: - - get - - list diff --git a/config/internal/mcad/clusterrolebinding_hpa-controller-custom-metrics.yaml.tmpl b/config/internal/mcad/clusterrolebinding_hpa-controller-custom-metrics.yaml.tmpl deleted file mode 100644 index e4a482fe..00000000 --- a/config/internal/mcad/clusterrolebinding_hpa-controller-custom-metrics.yaml.tmpl +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: hpa-controller-custom-metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{.Name}}-mcad-custom-metrics-server-admin-role - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -subjects: - - kind: ServiceAccount - name: horizontal-pod-autoscaler - namespace: kube-system diff --git a/config/internal/mcad/clusterrolebinding_mcad-controller-kube-scheduler.yaml.tmpl b/config/internal/mcad/clusterrolebinding_mcad-controller-kube-scheduler.yaml.tmpl deleted file mode 100644 index f01636b1..00000000 --- a/config/internal/mcad/clusterrolebinding_mcad-controller-kube-scheduler.yaml.tmpl +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - labels: - kubernetes.io/bootstrapping: rbac-defaults - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} - name: {{.Name}}-mcad-controller-kube-scheduler-crb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-scheduler -subjects: - - kind: ServiceAccount - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/internal/mcad/clusterrolebinding_mcad-controller.yaml.tmpl b/config/internal/mcad/clusterrolebinding_mcad-controller.yaml.tmpl deleted file mode 100644 index 6ef7ff52..00000000 --- a/config/internal/mcad/clusterrolebinding_mcad-controller.yaml.tmpl +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - labels: - kubernetes.io/bootstrapping: rbac-defaults - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} - name: {{.Name}}-mcad-controller-crb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{.Name}}-mcad-controller-role -subjects: - - kind: ServiceAccount - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/internal/mcad/clusterrolebinding_mcad-edit.yaml.tmpl b/config/internal/mcad/clusterrolebinding_mcad-edit.yaml.tmpl deleted file mode 100644 index 06b0f12d..00000000 --- a/config/internal/mcad/clusterrolebinding_mcad-edit.yaml.tmpl +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - labels: - kubernetes.io/bootstrapping: rbac-defaults - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} - name: {{.Name}}-mcad-edit-crb -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edit -subjects: - - kind: ServiceAccount - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/internal/mcad/clusterrolebinding_mcad-system-auth-delegator.yaml.tmpl b/config/internal/mcad/clusterrolebinding_mcad-system-auth-delegator.yaml.tmpl deleted file mode 100644 index fc66e588..00000000 --- a/config/internal/mcad/clusterrolebinding_mcad-system-auth-delegator.yaml.tmpl +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{.Name}}-mcad-system:auth-delegator - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:auth-delegator -subjects: - - kind: ServiceAccount - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/internal/mcad/clusterrolebinding_metrics-resource-reader.yaml.tmpl b/config/internal/mcad/clusterrolebinding_metrics-resource-reader.yaml.tmpl deleted file mode 100644 index 9d4327e4..00000000 --- a/config/internal/mcad/clusterrolebinding_metrics-resource-reader.yaml.tmpl +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{.Name}}-mcad-metrics-resource-reader-crb - labels: - app.kubernetes.io/managed-by: MCAD - codeflare.codeflare.dev/cr-name: {{.Name}} - codeflare.codeflare.dev/cr-namespace: {{.Namespace}} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{.Name}}-mcad-metrics-resource-reader-role -subjects: - - kind: ServiceAccount - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/internal/mcad/configmap.yaml.tmpl b/config/internal/mcad/configmap.yaml.tmpl deleted file mode 100644 index c99b4a70..00000000 --- a/config/internal/mcad/configmap.yaml.tmpl +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -data: - DISPATCHER_MODE: "{{.DispatcherMode}}" - PREEMPTION: "{{.PreemptionEnabled}}" - {{if ne .AgentConfigs ""}}DISPATCHER_AGENT_CONFIGS: "{{.AgentConfigs}}"{{end}} - {{if ne .QuotaRestURL ""}}QUOTA_REST_URL: "{{.QuotaRestURL}}"{{end}} - {{if ne .PodCreationTimeout -1}}DISPATCH_RESOURCE_RESERVATION_TIMEOUT: "{{.PodCreationTimeout}}"{{end}} -kind: ConfigMap -metadata: - name: mcad-{{.Name}}-config - namespace: {{.Namespace}} - labels: - app: mcad-{{.Name}} - component: multi-cluster-app-dispatcher diff --git a/config/internal/mcad/deployment.yaml.tmpl b/config/internal/mcad/deployment.yaml.tmpl deleted file mode 100644 index 56cc691f..00000000 --- a/config/internal/mcad/deployment.yaml.tmpl +++ /dev/null @@ -1,58 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} - labels: - app: mcad-{{.Name}} - component: multi-cluster-application-dispatcher -spec: - replicas: 1 - selector: - matchLabels: - app: mcad-{{.Name}} - template: - metadata: - labels: - app: mcad-{{.Name}} - component: multi-cluster-application-dispatcher - spec: - containers: - - name: mcad-controller - args: ["--v", "4", "--logtostderr"] - command: - - mcad-controller - envFrom: - - configMapRef: - name: mcad-{{.Name}}-config - image: {{.ControllerImage}} - imagePullPolicy: Always - ports: - - name: https - containerPort: 6443 - protocol: TCP - - name: http - containerPort: 8080 - protocol: TCP - resources: {{.ControllerResources}} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - name: temp-vol - mountPath: /tmp - livenessProbe: - httpGet: - path: /healthz - port: 8081 - timeoutSeconds: 5 - periodSeconds: 5 - readinessProbe: - httpGet: - path: /readyz - port: 8081 - timeoutSeconds: 5 - periodSeconds: 5 - serviceAccountName: mcad-controller-{{.Name}} - volumes: - - name: temp-vol - emptyDir: {} diff --git a/config/internal/mcad/image_secret.yaml b/config/internal/mcad/image_secret.yaml deleted file mode 100644 index 840c5069..00000000 --- a/config/internal/mcad/image_secret.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# {{ if .Values.imagePullSecret.name }} -apiVersion: v1 -kind: Secret -metadata: - name: {{.Values.imagePullSecret.name}} - namespace: kube-system -type: kubernetes.io/dockerconfigjson -data: - .dockerconfigjson: {{template "imagePullSecret" .}} -# {{ end }} diff --git a/config/internal/mcad/rolebinding_custom-metrics-auth-reader.yaml.tmpl b/config/internal/mcad/rolebinding_custom-metrics-auth-reader.yaml.tmpl deleted file mode 100644 index f8794545..00000000 --- a/config/internal/mcad/rolebinding_custom-metrics-auth-reader.yaml.tmpl +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{.Name}}-custom-metrics-auth-reader - namespace: kube-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader -subjects: - - kind: ServiceAccount - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/internal/mcad/service.yaml.tmpl b/config/internal/mcad/service.yaml.tmpl deleted file mode 100644 index 3bdd1555..00000000 --- a/config/internal/mcad/service.yaml.tmpl +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: mcad-{{.Name}}-metrics - namespace: {{.Namespace}} -spec: - ports: - - name: https - port: 443 - targetPort: 6443 - - name: http - port: 80 - targetPort: 8080 - selector: - app: mcad-{{.Name}} diff --git a/config/internal/mcad/service_nodeport.yaml b/config/internal/mcad/service_nodeport.yaml deleted file mode 100644 index f474e840..00000000 --- a/config/internal/mcad/service_nodeport.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# {{ if .Values.configMap.quotaRestUrl }} -apiVersion: v1 -kind: Service -metadata: - name: mcad-{{.Name}}-quota-http-server -spec: - type: NodePort - selector: - app: mcad-{{.Name}} - ports: - # By default and for convenience, the `targetPort` is set to the same value as the `port` field. - - port: 8082 - targetPort: 80 - # Optional field - # By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767) - nodePort: 30082 -# {{ end }} diff --git a/config/internal/mcad/serviceaccount.yaml.tmpl b/config/internal/mcad/serviceaccount.yaml.tmpl deleted file mode 100644 index c0418d24..00000000 --- a/config/internal/mcad/serviceaccount.yaml.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mcad-controller-{{.Name}} - namespace: {{.Namespace}} diff --git a/config/manager/controller_manager_config.yaml b/config/manager/controller_manager_config.yaml deleted file mode 100644 index ea5cfaa9..00000000 --- a/config/manager/controller_manager_config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 -kind: ControllerManagerConfig -health: - healthProbeBindAddress: :8081 -metrics: - bindAddress: 127.0.0.1:8080 -webhook: - port: 9443 -leaderElection: - leaderElect: true - resourceName: 5a3ca514.codeflare.dev -# leaderElectionReleaseOnCancel defines if the leader should step down volume -# when the Manager ends. This requires the binary to immediately end when the -# Manager is stopped, otherwise, this setting is unsafe. Setting this significantly -# speeds up voluntary leader transitions as the new leader don't have to wait -# LeaseDuration time first. -# In the default scaffold provided, the program ends immediately after -# the manager stops, so would be fine to enable this option. However, -# if you are doing or is intended to do any operation such as perform cleanups -# after the manager stops then its usage might be unsafe. -# leaderElectionReleaseOnCancel: true diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 538c69f2..bdb8b68d 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -5,8 +5,24 @@ generatorOptions: disableNameSuffixHash: true configMapGenerator: -- files: - - controller_manager_config.yaml - name: manager-config -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization +- name: stack-config + envs: + - params.env +configurations: + - params.yaml + +vars: +- name: namespace + objref: + kind: ConfigMap + name: stack-config + apiVersion: v1 + fieldref: + fieldpath: data.namespace +- name: codeflare_operator_controller_image + objref: + kind: ConfigMap + name: stack-config + apiVersion: v1 + fieldref: + fieldpath: data.codeflare-operator-controller-image diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 59b41783..14f62ad4 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -1,8 +1,3 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: system ---- apiVersion: apps/v1 kind: Deployment metadata: @@ -28,15 +23,13 @@ spec: # it is recommended to ensure that all your Pods/Containers are restrictive. # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted # Please uncomment the following code if your project does NOT have to work on old Kubernetes - # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). + # versions < 1.20 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). # seccompProfile: # type: RuntimeDefault containers: - command: - /manager - args: - - --leader-elect - image: controller:latest + image: $(codeflare_operator_controller_image) imagePullPolicy: Always name: manager securityContext: @@ -44,6 +37,15 @@ spec: capabilities: drop: - "ALL" + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + ports: + - containerPort: 8080 + protocol: TCP + name: metrics livenessProbe: httpGet: path: /healthz @@ -58,10 +60,10 @@ spec: periodSeconds: 10 resources: limits: - cpu: 500m - memory: 128Mi + cpu: "1" + memory: 1Gi requests: - cpu: 10m - memory: 64Mi + cpu: "1" + memory: 1Gi serviceAccountName: controller-manager terminationGracePeriodSeconds: 10 diff --git a/config/manager/params.env b/config/manager/params.env new file mode 100644 index 00000000..6ac22e10 --- /dev/null +++ b/config/manager/params.env @@ -0,0 +1,2 @@ +codeflare-operator-controller-image=quay.io/opendatahub/codeflare-operator:v1.4.0 +namespace=opendatahub diff --git a/config/manager/params.yaml b/config/manager/params.yaml new file mode 100644 index 00000000..4d4bd9d6 --- /dev/null +++ b/config/manager/params.yaml @@ -0,0 +1,5 @@ +varReference: + - path: subjects[]/namespace + kind: ClusterRoleBinding + - path: spec/template/spec/containers[]/image + kind: Deployment diff --git a/config/manifests/bases/codeflare-operator.clusterserviceversion.yaml b/config/manifests/bases/codeflare-operator.clusterserviceversion.yaml index 1a45a5a7..f47cdd1a 100644 --- a/config/manifests/bases/codeflare-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/codeflare-operator.clusterserviceversion.yaml @@ -2,7 +2,45 @@ apiVersion: operators.coreos.com/v1alpha1 kind: ClusterServiceVersion metadata: annotations: - alm-examples: '[]' + alm-examples: |- + [{ + "apiVersion": "workload.codeflare.dev/v1beta1", + "kind": "AppWrapper", + "metadata": {"name": "0001-aw-generic-deployment-1"}, + "spec": { + "resources": { + "GenericItems": [{ + "replicas": 1, + "generictemplate": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "0001-aw-generic-deployment-1", + "labels": {"app": "0001-aw-generic-deployment-1"} + }, + "spec": { + "selector": {"matchLabels": {"app": "0001-aw-generic-deployment-1"}}, + "replicas": 2, + "template": { + "metadata": {"labels": {"app": "0001-aw-generic-deployment-1"}}, + "spec": { + "containers": [{ + "name": "0001-aw-generic-deployment-1", + "image": "kicbase/echo-server:1.0", + "ports": [{"containerPort": 80}], + "resources": { + "requests": {"cpu": "100m", "memory": "256Mi"}, + "limits": {"cpu": "100m", "memory": "256Mi"} + } + }] + } + } + } + } + }] + } + } + }] capabilities: Basic Install categories: AI/Machine Learning, Big Data operatorframework.io/suggested-namespace: openshift-operators @@ -12,18 +50,7 @@ metadata: namespace: placeholder spec: apiservicedefinitions: {} - customresourcedefinitions: - owned: - - description: InstaScale is the Schema for the instascales API - displayName: InstaScale - kind: InstaScale - name: instascales.codeflare.codeflare.dev - version: v1alpha1 - - description: MCAD is the Schema for the mcads API - displayName: MCAD - kind: MCAD - name: mcads.codeflare.codeflare.dev - version: v1alpha1 + customresourcedefinitions: {} description: CodeFlare allows you to scale complex pipelines anywhere displayName: CodeFlare Operator icon: @@ -45,9 +72,7 @@ spec: keywords: - Pipelines - Scaling - - MCAD - App - - InstaScale - Jobs links: - name: Codeflare Operator diff --git a/config/manifests/kustomization.yaml b/config/manifests/kustomization.yaml index 954c255a..161a419d 100644 --- a/config/manifests/kustomization.yaml +++ b/config/manifests/kustomization.yaml @@ -1,9 +1,9 @@ # These resources constitute the fully configured set of manifests # used to generate the 'manifests/' directory in a bundle. resources: -- bases/codeflare-operator.clusterserviceversion.yaml - ../default -- ../samples - ../scorecard +- bases/codeflare-operator.clusterserviceversion.yaml + apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization diff --git a/config/odh-operator/kustomization.yaml b/config/odh-operator/kustomization.yaml new file mode 100644 index 00000000..02358bd9 --- /dev/null +++ b/config/odh-operator/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- odh.yaml diff --git a/config/odh-operator/odh.yaml b/config/odh-operator/odh.yaml new file mode 100644 index 00000000..6f752159 --- /dev/null +++ b/config/odh-operator/odh.yaml @@ -0,0 +1,13 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: opendatahub-operator + labels: + operators.coreos.com/opendatahub-operator.openshift-operators: '' + namespace: openshift-operators +spec: + channel: fast + name: opendatahub-operator + installPlanApproval: Automatic + source: community-operators + sourceNamespace: openshift-marketplace diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml deleted file mode 100644 index 51a75db4..00000000 --- a/config/rbac/auth_proxy_client_clusterrole.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics-reader -rules: -- nonResourceURLs: - - "/metrics" - verbs: - - get diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml deleted file mode 100644 index 80e1857c..00000000 --- a/config/rbac/auth_proxy_role.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: proxy-role -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml deleted file mode 100644 index ec7acc0a..00000000 --- a/config/rbac/auth_proxy_role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: proxy-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/config/rbac/edit_role_binding.yaml b/config/rbac/edit_role_binding.yaml deleted file mode 100644 index 640ae1ba..00000000 --- a/config/rbac/edit_role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: manager-edit-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edit -subjects: - - kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/config/rbac/instascale_editor_role.yaml b/config/rbac/instascale_editor_role.yaml deleted file mode 100644 index 47530295..00000000 --- a/config/rbac/instascale_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit instascales. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: instascale-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: codeflare-operator - app.kubernetes.io/part-of: codeflare-operator - app.kubernetes.io/managed-by: kustomize - name: instascale-editor-role -rules: -- apiGroups: - - codeflare.codeflare.dev - resources: - - instascales - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - codeflare.codeflare.dev - resources: - - instascales/status - verbs: - - get diff --git a/config/rbac/instascale_viewer_role.yaml b/config/rbac/instascale_viewer_role.yaml deleted file mode 100644 index ca4fc68e..00000000 --- a/config/rbac/instascale_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view instascales. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: instascale-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: codeflare-operator - app.kubernetes.io/part-of: codeflare-operator - app.kubernetes.io/managed-by: kustomize - name: instascale-viewer-role -rules: -- apiGroups: - - codeflare.codeflare.dev - resources: - - instascales - verbs: - - get - - list - - watch -- apiGroups: - - codeflare.codeflare.dev - resources: - - instascales/status - verbs: - - get diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 8a599efd..166fe798 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -7,13 +7,5 @@ resources: - service_account.yaml - role.yaml - role_binding.yaml -- edit_role_binding.yaml # We are using this binding as mcad requires this role - leader_election_role.yaml - leader_election_role_binding.yaml -# Comment the following 4 lines if you want to disable -# the auth proxy (https://github.com/brancz/kube-rbac-proxy) -# which protects your /metrics endpoint. -- auth_proxy_service.yaml -- auth_proxy_role.yaml -- auth_proxy_role_binding.yaml -- auth_proxy_client_clusterrole.yaml diff --git a/config/rbac/mcad_editor_role.yaml b/config/rbac/mcad_editor_role.yaml deleted file mode 100644 index f82b9507..00000000 --- a/config/rbac/mcad_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit mcads. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: mcad-editor-role -rules: -- apiGroups: - - codeflare.codeflare.dev - resources: - - mcads - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - codeflare.codeflare.dev - resources: - - mcads/status - verbs: - - get diff --git a/config/rbac/mcad_viewer_role.yaml b/config/rbac/mcad_viewer_role.yaml deleted file mode 100644 index df4526d2..00000000 --- a/config/rbac/mcad_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view mcads. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: mcad-viewer-role -rules: -- apiGroups: - - codeflare.codeflare.dev - resources: - - mcads - verbs: - - get - - list - - watch -- apiGroups: - - codeflare.codeflare.dev - resources: - - mcads/status - verbs: - - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index ab9bc905..899e4915 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -6,266 +6,111 @@ metadata: name: manager-role rules: - apiGroups: - - '*' + - "" resources: - - deployments - - services + - secrets verbs: - - create - - delete - get - list - - patch - update - watch - apiGroups: - - apps + - admissionregistration.k8s.io resources: - - deployments + - mutatingwebhookconfigurations verbs: - - create - - delete - get - list - - patch - update - watch - apiGroups: - - apps + - admissionregistration.k8s.io resources: - - deployments - - replicasets - - statefulsets + - validatingwebhookconfigurations verbs: - - create - - delete - get - list - - patch - update - watch - apiGroups: - - codeflare.codeflare.dev + - authentication.k8s.io resources: - - instascales + - tokenreviews verbs: - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - codeflare.codeflare.dev - resources: - - instascales/finalizers - verbs: - - update - apiGroups: - - codeflare.codeflare.dev + - authorization.k8s.io resources: - - instascales/status - verbs: - - get - - patch - - update -- apiGroups: - - codeflare.codeflare.dev - resources: - - mcads + - subjectaccessreviews verbs: - create - - delete - - get - - list - - patch - - update - - watch - apiGroups: - - codeflare.codeflare.dev + - config.openshift.io resources: - - mcads/finalizers - verbs: - - update -- apiGroups: - - codeflare.codeflare.dev - resources: - - mcads/status + - ingresses verbs: - get - - patch - - update -- apiGroups: - - coordination.k8s.io - resources: - - kube-scheduler - - leases - verbs: - - create - - get - - update -- apiGroups: - - "" - resources: - - bindings - - pods/binding - verbs: - - create - apiGroups: - "" resources: - - configmaps - - nodes - - persistentvolumeclaims - - persistentvolumes - secrets - - serviceaccounts - - services verbs: - create - delete - get - - list - patch - - update - - watch - apiGroups: - "" resources: - - configmaps - - persistentvolumeclaims - - persistentvolumes - - secrets - serviceaccounts - - services verbs: - create - delete - get - - list - patch - update - - watch - apiGroups: - "" resources: - - endpoints - - kube-scheduler - verbs: - - create - - get - - update -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - update -- apiGroups: - - "" - resources: - - kube-scheduler - verbs: - - get - - update -- apiGroups: - - "" - resources: - - lists - - namespaces - - pods + - services verbs: - create - delete - - deletecollection - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims - - persistentvolumes - verbs: - - '*' -- apiGroups: - - "" - resources: - - pods/status - verbs: - patch - update - apiGroups: - - "" + - dscinitialization.opendatahub.io resources: - - replicationcontrollers + - dscinitializations verbs: - get - list - watch - apiGroups: - - custom.metrics.k8s.io + - networking.k8s.io resources: - - '*' - verbs: - - '*' -- apiGroups: - - events.k8s.io - resources: - - events - - kube-scheduler - verbs: - - create - - patch - - update -- apiGroups: - - extensions - resources: - - replicasets - verbs: - - get - - list - - watch -- apiGroups: - - machine.openshift.io - resources: - - '*' + - ingresses verbs: - create - delete - get - - list - patch - update - - watch - apiGroups: - - mcad.ibm.com + - networking.k8s.io resources: - - appwrappers - - appwrappers/finalizers - - appwrappers/status - - queuejobs - - schedulingspecs + - networkpolicies verbs: - create - delete - - deletecollection - get - - list - patch - update - - watch - apiGroups: - - mcad.ibm.com + - ray.io resources: - - appwrappers - - queuejobs - - schedulingspecs + - rayclusters verbs: - create - delete @@ -275,58 +120,37 @@ rules: - update - watch - apiGroups: - - policy + - ray.io resources: - - poddisruptionbudgets + - rayclusters/finalizers verbs: - - get - - list - - watch + - update - apiGroups: - - rbac.authorization.k8s.io + - ray.io resources: - - clusterrolebindings - - clusterroles + - rayclusters/status verbs: - - create - - delete - get - - list + - patch - update - - watch - apiGroups: - rbac.authorization.k8s.io resources: - - rolebindings - - roles + - clusterrolebindings verbs: - create - delete - get - - list - patch - update - - watch - apiGroups: - - scheduling.sigs.k8s.io + - route.openshift.io resources: - - podgroups + - routes + - routes/custom-host verbs: - create - delete - - deletecollection - get - - list - patch - update - - watch -- apiGroups: - - storage.k8s.io - resources: - - csidrivers - - csinodes - - csistoragecapacities - verbs: - - get - - list - - watch diff --git a/config/samples/codeflare_v1alpha1_instascale.yaml b/config/samples/codeflare_v1alpha1_instascale.yaml deleted file mode 100644 index 033cab0c..00000000 --- a/config/samples/codeflare_v1alpha1_instascale.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: InstaScale -metadata: - labels: - app.kubernetes.io/name: instascale - app.kubernetes.io/instance: instascale-sample - app.kubernetes.io/part-of: codeflare-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: codeflare-operator - name: instascale-sample -spec: {} - # TODO(user): Add fields here diff --git a/config/samples/codeflare_v1alpha1_mcad.yaml b/config/samples/codeflare_v1alpha1_mcad.yaml deleted file mode 100644 index 624db497..00000000 --- a/config/samples/codeflare_v1alpha1_mcad.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: MCAD -metadata: - name: mcad-sample -spec: {} - # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml deleted file mode 100644 index 5a242aff..00000000 --- a/config/samples/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -## Append samples you want in your CSV to this file as resources ## -resources: -- codeflare_v1alpha1_mcad.yaml -- codeflare_v1alpha1_instascale.yaml -#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml new file mode 100644 index 00000000..297cf8a8 --- /dev/null +++ b/config/webhook/kustomization.yaml @@ -0,0 +1,7 @@ +resources: +- manifests.yaml +- service.yaml +- secret.yaml + +configurations: +- kustomizeconfig.yaml diff --git a/config/webhook/kustomizeconfig.yaml b/config/webhook/kustomizeconfig.yaml new file mode 100644 index 00000000..25e21e3c --- /dev/null +++ b/config/webhook/kustomizeconfig.yaml @@ -0,0 +1,25 @@ +# the following config is for teaching kustomize where to look at when substituting vars. +# It requires kustomize v2.1.0 or newer to work properly. +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + - kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + +namespace: +- kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true +- kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true + +varReference: +- path: metadata/annotations diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml new file mode 100644 index 00000000..5e98107c --- /dev/null +++ b/config/webhook/manifests.yaml @@ -0,0 +1,53 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + creationTimestamp: null + name: mutating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-ray-io-v1-raycluster + failurePolicy: Fail + name: mraycluster.ray.openshift.ai + rules: + - apiGroups: + - ray.io + apiVersions: + - v1 + operations: + - CREATE + resources: + - rayclusters + sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-ray-io-v1-raycluster + failurePolicy: Fail + name: vraycluster.ray.openshift.ai + rules: + - apiGroups: + - ray.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - rayclusters + sideEffects: None diff --git a/config/webhook/secret.yaml b/config/webhook/secret.yaml new file mode 100644 index 00000000..af960e6c --- /dev/null +++ b/config/webhook/secret.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: Secret +metadata: + name: webhook-server-cert + namespace: system diff --git a/config/webhook/service.yaml b/config/webhook/service.yaml new file mode 100644 index 00000000..01a9f23d --- /dev/null +++ b/config/webhook/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: webhook-service +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + selector: + app.kubernetes.io/part-of: codeflare + app.kubernetes.io/name: codeflare-operator diff --git a/contrib/configuration/basic-dsc.yaml b/contrib/configuration/basic-dsc.yaml new file mode 100644 index 00000000..de992636 --- /dev/null +++ b/contrib/configuration/basic-dsc.yaml @@ -0,0 +1,31 @@ +apiVersion: datasciencecluster.opendatahub.io/v1 +kind: DataScienceCluster +metadata: + labels: + app.kubernetes.io/created-by: opendatahub-operator + app.kubernetes.io/instance: default + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: datasciencecluster + app.kubernetes.io/part-of: opendatahub-operator + name: example-dsc +spec: + components: + codeflare: + devFlags: + manifests: + - uri: '' + contextDir: 'config' + sourcePath: 'default' + managementState: Managed + dashboard: + managementState: Managed + datasciencepipelines: + managementState: Removed + kserve: + managementState: Removed + modelmeshserving: + managementState: Removed + ray: + managementState: Managed + workbenches: + managementState: Managed diff --git a/controllers/config/manifest.go b/controllers/config/manifest.go deleted file mode 100644 index 2360100d..00000000 --- a/controllers/config/manifest.go +++ /dev/null @@ -1,17 +0,0 @@ -package config - -import ( - "github.com/go-logr/logr" - mfc "github.com/manifestival/controller-runtime-client" - mf "github.com/manifestival/manifestival" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func Manifest(cl client.Client, templatePath string, context interface{}, name string, logger logr.Logger) (mf.Manifest, error) { - m, err := mf.ManifestFrom(PathTemplateSource(templatePath, context, name), mf.UseLogger(logger)) - if err != nil { - return mf.Manifest{}, err - } - m.Client = mfc.NewClient(cl) - return m, err -} diff --git a/controllers/config/templating.go b/controllers/config/templating.go deleted file mode 100644 index cfaddf5a..00000000 --- a/controllers/config/templating.go +++ /dev/null @@ -1,48 +0,0 @@ -package config - -import ( - "bytes" - "io" - "os" - "text/template" - - mf "github.com/manifestival/manifestival" -) - -// PathPrefix is the file system path which template paths will be prefixed with. -// Default is no prefix, which causes paths to be read relative to process working dir -var PathPrefix string - -// PathTemplateSource A templating source read from a file -func PathTemplateSource(path string, context interface{}, name string) mf.Source { - f, err := os.Open(prefixedPath(path)) - if err != nil { - panic(err) - } - return templateSource(f, context, name) -} - -func prefixedPath(p string) string { - if PathPrefix != "" { - return PathPrefix + "/" + p - } - return p -} - -// A templating manifest source -func templateSource(r io.Reader, context interface{}, name string) mf.Source { - b, err := io.ReadAll(r) - if err != nil { - panic(err) - } - t, err := template.New(name).Parse(string(b)) - if err != nil { - panic(err) - } - var b2 bytes.Buffer - err = t.Execute(&b2, context) - if err != nil { - panic(err) - } - return mf.Reader(&b2) -} diff --git a/controllers/defaults.go b/controllers/defaults.go deleted file mode 100644 index d3cac3d0..00000000 --- a/controllers/defaults.go +++ /dev/null @@ -1,10 +0,0 @@ -package controllers - -// *********************** -// DO NOT EDIT THIS FILE -// *********************** - -const ( - MCADImage = "quay.io/project-codeflare/mcad-controller:release-v1.31.0" - InstaScaleImage = "quay.io/project-codeflare/instascale-controller:v0.0.4" -) diff --git a/controllers/instascale.go b/controllers/instascale.go deleted file mode 100644 index 3a35e05a..00000000 --- a/controllers/instascale.go +++ /dev/null @@ -1,26 +0,0 @@ -package controllers - -import ( - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" -) - -var instascaleTemplates = []string{ - "instascale/configmap.yaml.tmpl", - "instascale/sa.yaml.tmpl", - "instascale/clusterrole.yaml.tmpl", - "instascale/clusterrolebinding.yaml.tmpl", - "instascale/deployment.yaml.tmpl", -} - -func (r *InstaScaleReconciler) ReconcileInstaScale(instascale *codeflarev1alpha1.InstaScale, params *InstaScaleParams) error { - - for _, template := range instascaleTemplates { - err := r.Apply(instascale, params, template) - if err != nil { - return err - } - } - - r.Log.Info("Finished applying InstaScale Resources") - return nil -} diff --git a/controllers/instascale_controller.go b/controllers/instascale_controller.go deleted file mode 100644 index 31fcb53b..00000000 --- a/controllers/instascale_controller.go +++ /dev/null @@ -1,241 +0,0 @@ -/* -Copyright 2023. - -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 controllers - -import ( - "context" - "fmt" - "path" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - authv1 "k8s.io/api/rbac/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/go-logr/logr" - mf "github.com/manifestival/manifestival" - - "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "github.com/project-codeflare/codeflare-operator/controllers/config" - "github.com/project-codeflare/codeflare-operator/controllers/util" -) - -// InstaScaleReconciler reconciles a InstaScale object -type InstaScaleReconciler struct { - client.Client - Scheme *runtime.Scheme - Log logr.Logger - TemplatesPath string -} - -var instascaleClusterScopedTemplates = []string{ - "instascale/clusterrole.yaml.tmpl", - "instascale/clusterrolebinding.yaml.tmpl", -} - -func (r *InstaScaleReconciler) Apply(owner mf.Owner, params *InstaScaleParams, template string, fns ...mf.Transformer) error { - tmplManifest, err := config.Manifest(r.Client, path.Join(r.TemplatesPath, template), params, template, r.Log) - if err != nil { - return fmt.Errorf("error loading template yaml: %w", err) - } - tmplManifest, err = tmplManifest.Transform( - mf.InjectOwner(owner), - ) - if err != nil { - return err - } - - tmplManifest, err = tmplManifest.Transform(fns...) - if err != nil { - return err - } - - return tmplManifest.Apply() -} - -// TODO: Review node permissions, instascale should only require read - -// +kubebuilder:rbac:groups=codeflare.codeflare.dev,resources=instascales,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=codeflare.codeflare.dev,resources=instascales/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=codeflare.codeflare.dev,resources=instascales/finalizers,verbs=update -// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=*,resources=deployments;services,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=secrets;configmaps;nodes;services;serviceaccounts;persistentvolumes;persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=persistentvolumes;persistentvolumeclaims,verbs=* -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles;rolebindings,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings,verbs=get;list;watch;create;update;delete -// +kubebuilder:rbac:groups=machine.openshift.io,resources=*,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=mcad.ibm.com,resources=appwrappers;queuejobs;schedulingspecs,verbs=get;list;watch;create;update;patch;delete - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the InstaScale object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile -func (r *InstaScaleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.WithValues("namespace", req.Namespace) - - log.V(1).Info("InstaScale reconciler called.") - - params := &InstaScaleParams{} - instascaleCustomResource := &v1alpha1.InstaScale{} - - err := r.Get(ctx, req.NamespacedName, instascaleCustomResource) - if err != nil && apierrs.IsNotFound(err) { - log.Info("Stop InstaScale reconciliation") - return ctrl.Result{}, nil - } else if err != nil { - log.Error(err, "Unable to fetch the InstaScale custom resource") - return ctrl.Result{}, err - } - - // FixMe: Hack for stubbing gvk during tests as these are not populated by test suite - // Refer to https://github.com/operator-framework/operator-sdk/issues/727#issuecomment-581169171 - // In production we expect these to be populated - if instascaleCustomResource.Kind == "" { - instascaleCustomResource = instascaleCustomResource.DeepCopy() - gvk := v1alpha1.SchemeGroupVersion.WithKind("InstaScale") - instascaleCustomResource.APIVersion, instascaleCustomResource.Kind = gvk.Version, gvk.Kind - } - - params.ExtractParams(instascaleCustomResource) - - if instascaleCustomResource.ObjectMeta.DeletionTimestamp.IsZero() { - if !controllerutil.ContainsFinalizer(instascaleCustomResource, finalizerName) { - controllerutil.AddFinalizer(instascaleCustomResource, finalizerName) - if err := r.Update(ctx, instascaleCustomResource); err != nil { - return ctrl.Result{}, err - } - } - } else { - if controllerutil.ContainsFinalizer(instascaleCustomResource, finalizerName) { - if err := r.cleanUpClusterResources(params); err != nil { - return ctrl.Result{}, err - } - controllerutil.RemoveFinalizer(instascaleCustomResource, finalizerName) - if err := r.Update(ctx, instascaleCustomResource); err != nil { - return ctrl.Result{}, err - } - } - - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - err = r.ReconcileInstaScale(instascaleCustomResource, params) - if err != nil { - return ctrl.Result{}, err - } - - err = updateInstascaleReadyStatus(ctx, r, req, instascaleCustomResource) - if err != nil { - return ctrl.Result{}, err - } - - err = r.Client.Status().Update(ctx, instascaleCustomResource) - if err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func updateInstascaleReadyStatus(ctx context.Context, r *InstaScaleReconciler, req ctrl.Request, instascaleCustomResource *v1alpha1.InstaScale) error { - deployment := &appsv1.Deployment{} - err := r.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("instascale-%s", req.Name), Namespace: req.Namespace}, deployment) - if err != nil { - return err - } - r.Log.Info("Checking if deployment is ready.") - instascaleCustomResource.Status.Ready = util.IsDeploymentReady(deployment) - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *InstaScaleReconciler) SetupWithManager(mgr ctrl.Manager) error { - crFromLabels := handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request { - labels := o.GetLabels() - if labels["app.kubernetes.io/managed-by"] == "InstaScale" { - crName := labels["codeflare.codeflare.dev/cr-name"] - crNamespace := labels["codeflare.codeflare.dev/cr-namespace"] - if crName != "" { - return []reconcile.Request{ - {NamespacedName: types.NamespacedName{ - Name: crName, - Namespace: crNamespace, - }}, - } - } - } - return nil - }) - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.InstaScale{}). - Owns(&corev1.ConfigMap{}). - Owns(&corev1.ServiceAccount{}). - Owns(&authv1.ClusterRole{}). - Owns(&authv1.ClusterRoleBinding{}). - Owns(&appsv1.Deployment{}). - Watches( - &source.Kind{Type: &rbacv1.ClusterRole{}}, - crFromLabels, - ). - Watches( - &source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, - crFromLabels, - ). - Complete(r) -} - -func (r *InstaScaleReconciler) DeleteResource(params *InstaScaleParams, template string, fns ...mf.Transformer) error { - tmplManifest, err := config.Manifest(r.Client, r.TemplatesPath+template, params, template, r.Log) - if err != nil { - return fmt.Errorf("error loading template yaml: %w", err) - } - - tmplManifest, err = tmplManifest.Transform(fns...) - if err != nil { - return err - } - - return tmplManifest.Delete() -} - -// cleanUpClusterResources will be responsible for deleting objects that do not have owner references set -func (r *InstaScaleReconciler) cleanUpClusterResources(params *InstaScaleParams) error { - for _, template := range instascaleClusterScopedTemplates { - err := r.DeleteResource(params, template) - if err != nil { - return err - } - } - return nil -} diff --git a/controllers/instascale_controller_test.go b/controllers/instascale_controller_test.go deleted file mode 100644 index 4071c515..00000000 --- a/controllers/instascale_controller_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package controllers - -import ( - "context" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - mfc "github.com/manifestival/controller-runtime-client" - mf "github.com/manifestival/manifestival" - - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" -) - -const ( - instascaleCRCase1 = "./testdata/instascale_test_cases/case_1.yaml" - instascaleCRCase2 = "./testdata/instascale_test_cases/case_2.yaml" - instascaleCRCase3 = "./testdata/instascale_test_cases/case_3.yaml" - instascaleConfigMap1 = "./testdata/instascale_test_results/case_1/configmap.yaml" - instascaleServiceAccount1 = "./testdata/instascale_test_results/case_1/serviceaccount.yaml" - instascaleClusterRole1 = "./testdata/instascale_test_results/case_1/clusterrole.yaml" - instascaleClusterRoleBinding1 = "./testdata/instascale_test_results/case_1/clusterrolebinding.yaml" - instascaleDeployment1 = "./testdata/instascale_test_results/case_1/deployment.yaml" - instascaleDeployment2 = "./testdata/instascale_test_results/case_2/deployment.yaml" - instascaleDeployment3 = "./testdata/instascale_test_results/case_3/deployment.yaml" -) - -func deployInstaScale(ctx context.Context, path string, opts mf.Option) { - instascale := &codeflarev1alpha1.InstaScale{} - err := convertToStructuredResource(path, instascale, opts) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, instascale)).Should(Succeed()) -} - -var _ = Describe("The Instascale Controller", func() { - client := mfc.NewClient(k8sClient) - opts := mf.UseClient(client) - ctx := context.Background() - - Context("In a namespace, when a blank InstaScale Custom Resource is deployed", func() { - - It("It should deploy InstaScale with default settings", func() { - deployInstaScale(ctx, instascaleCRCase1, opts) - compareConfigMaps(instascaleConfigMap1, opts) - compareServiceAccounts(instascaleServiceAccount1, opts) - compareDeployments(instascaleDeployment1, opts) - compareClusterRoles(instascaleClusterRole1, opts) - compareClusterRoleBindings(instascaleClusterRoleBinding1, opts) - }) - }) - - Context("In a namespace, InstaScale ControllerResources is given", func() { - - It("It should deploy InstaScale with the given ControllerResources", func() { - deployInstaScale(ctx, instascaleCRCase2, opts) - compareDeployments(instascaleDeployment2, opts) - }) - }) - - Context("When an InstaScale resource with a custom image is given", func() { - - It("It should deploy InstaScale with the given controller image", func() { - deployInstaScale(ctx, instascaleCRCase3, opts) - compareDeployments(instascaleDeployment3, opts) - }) - }) -}) diff --git a/controllers/instascale_params.go b/controllers/instascale_params.go deleted file mode 100644 index 0def6935..00000000 --- a/controllers/instascale_params.go +++ /dev/null @@ -1,61 +0,0 @@ -package controllers - -import ( - "encoding/json" - - "github.com/manifestival/manifestival" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - - instascalev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" -) - -type InstaScaleParams struct { - Name string - Namespace string - Owner manifestival.Owner - EnableMonitoring bool - MaxScaleoutAllowed int - UseMachinePools bool - ControllerResources ControllerResources - ControllerImage string -} - -type ControllerResources struct { - v1.ResourceRequirements -} - -func (c *ControllerResources) String() string { - raw, err := json.Marshal(c) - if err != nil { - return "{}" - } - return string(raw) -} - -func (p *InstaScaleParams) ExtractParams(instascale *instascalev1alpha1.InstaScale) { - p.Name = instascale.Name - p.Namespace = instascale.Namespace - p.ControllerImage = instascale.Spec.ControllerImage - if p.ControllerImage == "" { - p.ControllerImage = InstaScaleImage - } - p.Owner = instascale - p.EnableMonitoring = instascale.Spec.EnableMonitoring - p.MaxScaleoutAllowed = instascale.Spec.MaxScaleoutAllowed - p.UseMachinePools = instascale.Spec.UseMachinePools - if instascale.Spec.ControllerResources == nil { - p.ControllerResources = ControllerResources{ - v1.ResourceRequirements{ - Limits: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("2"), - v1.ResourceMemory: resource.MustParse("2G")}, - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("200m"), - v1.ResourceMemory: resource.MustParse("200M")}, - }} - } else { - p.ControllerResources = ControllerResources{*instascale.Spec.ControllerResources} - } -} diff --git a/controllers/mcad_controller.go b/controllers/mcad_controller.go deleted file mode 100644 index f21023cd..00000000 --- a/controllers/mcad_controller.go +++ /dev/null @@ -1,247 +0,0 @@ -/* -Copyright 2023. - -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 controllers - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - mf "github.com/manifestival/manifestival" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "github.com/project-codeflare/codeflare-operator/controllers/config" - "github.com/project-codeflare/codeflare-operator/controllers/util" -) - -const finalizerName = "codeflare.codeflare.dev/finalizer" - -// MCADReconciler reconciles a MCAD object -type MCADReconciler struct { - client.Client - Scheme *runtime.Scheme - Log logr.Logger - TemplatesPath string -} - -func (r *MCADReconciler) Apply(owner mf.Owner, params *MCADParams, template string, fns ...mf.Transformer) error { - tmplManifest, err := config.Manifest(r.Client, r.TemplatesPath+template, params, template, r.Log) - if err != nil { - return fmt.Errorf("error loading template yaml: %w", err) - } - tmplManifest, err = tmplManifest.Transform( - mf.InjectOwner(owner), - ) - if err != nil { - return err - } - - tmplManifest, err = tmplManifest.Transform(fns...) - if err != nil { - return err - } - - return tmplManifest.Apply() -} - -func (r *MCADReconciler) ApplyWithoutOwner(params *MCADParams, template string, fns ...mf.Transformer) error { - tmplManifest, err := config.Manifest(r.Client, r.TemplatesPath+template, params, template, r.Log) - if err != nil { - return fmt.Errorf("error loading template yaml: %w", err) - } - - tmplManifest, err = tmplManifest.Transform(fns...) - if err != nil { - return err - } - - return tmplManifest.Apply() -} - -func (r *MCADReconciler) DeleteResource(params *MCADParams, template string, fns ...mf.Transformer) error { - tmplManifest, err := config.Manifest(r.Client, r.TemplatesPath+template, params, template, r.Log) - if err != nil { - return fmt.Errorf("error loading template yaml: %w", err) - } - - tmplManifest, err = tmplManifest.Transform(fns...) - if err != nil { - return err - } - - return tmplManifest.Delete() -} - -// +kubebuilder:rbac:groups=codeflare.codeflare.dev,resources=mcads,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=codeflare.codeflare.dev,resources=mcads/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=codeflare.codeflare.dev,resources=mcads/finalizers,verbs=update -// +kubebuilder:rbac:groups=mcad.ibm.com,resources=queuejobs;schedulingspecs;appwrappers;appwrappers/finalizers;appwrappers/status,verbs=get;list;watch;create;update;patch;delete;deletecollection -// +kubebuilder:rbac:groups=core,resources=pods;lists;namespaces,verbs=get;list;watch;create;update;patch;delete;deletecollection -// +kubebuilder:rbac:groups=core,resources=bindings;pods/binding,verbs=create -// +kubebuilder:rbac:groups=core,resources=kube-scheduler,verbs=get;update -// +kubebuilder:rbac:groups=core,resources=endpoints;kube-scheduler,verbs=create;get;update -// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch;update -// +kubebuilder:rbac:groups=core,resources=pods/status,verbs=patch;update -// +kubebuilder:rbac:groups=core,resources=replicationcontrollers,verbs=get;list;watch -// +kubebuilder:rbac:groups=scheduling.sigs.k8s.io,resources=podgroups,verbs=get;list;watch;create;update;patch;delete;deletecollection -// +kubebuilder:rbac:groups=apps,resources=deployments;replicasets;statefulsets,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=*,resources=deployments;services,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=secrets;configmaps;services;serviceaccounts;persistentvolumes;persistentvolumeclaims,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=core,resources=persistentvolumes;persistentvolumeclaims,verbs=* -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles;rolebindings,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings,verbs=get;list;watch;create;update;delete -// +kubebuilder:rbac:groups=custom.metrics.k8s.io,resources=*,verbs=* -// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases;kube-scheduler,verbs=create;update;get -// +kubebuilder:rbac:groups=events.k8s.io,resources=events;kube-scheduler,verbs=create;update;patch -// +kubebuilder:rbac:groups=extensions,resources=replicasets,verbs=get;list;watch -// +kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=get;list;watch -// +kubebuilder:rbac:groups=storage.k8s.io,resources=csidrivers;csinodes;csistoragecapacities,verbs=get;list;watch - -func (r *MCADReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := r.Log.WithValues("namespace", req.Namespace) - - log.V(1).Info("MCAD reconciler called.") - - params := &MCADParams{} - mcadCustomResource := &v1alpha1.MCAD{} - - err := r.Get(ctx, req.NamespacedName, mcadCustomResource) - if err != nil && apierrs.IsNotFound(err) { - log.Info("Stop MCAD reconciliation") - return ctrl.Result{}, nil - } else if err != nil { - log.Error(err, "Unable to fetch the MCAD custom resource") - return ctrl.Result{}, err - } - - // FixMe: Hack for stubbing gvk during tests as these are not populated by test suite - // Refer to https://github.com/operator-framework/operator-sdk/issues/727#issuecomment-581169171 - // In production we expect these to be populated - if mcadCustomResource.Kind == "" { - mcadCustomResource = mcadCustomResource.DeepCopy() - gvk := v1alpha1.SchemeGroupVersion.WithKind("MCAD") - mcadCustomResource.APIVersion, mcadCustomResource.Kind = gvk.Version, gvk.Kind - } - - params.ExtractParams(mcadCustomResource) - - if mcadCustomResource.ObjectMeta.DeletionTimestamp.IsZero() { - if !controllerutil.ContainsFinalizer(mcadCustomResource, finalizerName) { - controllerutil.AddFinalizer(mcadCustomResource, finalizerName) - if err := r.Update(ctx, mcadCustomResource); err != nil { - return ctrl.Result{}, err - } - } - } else { - if controllerutil.ContainsFinalizer(mcadCustomResource, finalizerName) { - if err := r.cleanUpOwnerLessResources(params); err != nil { - return ctrl.Result{}, err - } - controllerutil.RemoveFinalizer(mcadCustomResource, finalizerName) - if err := r.Update(ctx, mcadCustomResource); err != nil { - return ctrl.Result{}, err - } - } - - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - log.V(1).Info("ReconcileMCAD called.") - err = r.ReconcileMCAD(mcadCustomResource, params) - if err != nil { - return ctrl.Result{}, err - } - - err = updateMCADReadyStatus(ctx, r, req, mcadCustomResource) - if err != nil { - return ctrl.Result{}, err - } - err = r.Client.Status().Update(ctx, mcadCustomResource) - if err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func updateMCADReadyStatus(ctx context.Context, r *MCADReconciler, req ctrl.Request, mcadCustomResource *v1alpha1.MCAD) error { - deployment := &appsv1.Deployment{} - err := r.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("mcad-controller-%s", req.Name), Namespace: req.Namespace}, deployment) - if err != nil { - return err - } - r.Log.Info("Checking if MCAD deployment is ready.") - mcadCustomResource.Status.Ready = util.IsDeploymentReady(deployment) - return nil -} - -// SetupWithManager sets up the controller with the Manager. -func (r *MCADReconciler) SetupWithManager(mgr ctrl.Manager) error { - crFromLabels := handler.EnqueueRequestsFromMapFunc(func(o client.Object) []reconcile.Request { - labels := o.GetLabels() - if labels["app.kubernetes.io/managed-by"] == "MCAD" { - crName := labels["codeflare.codeflare.dev/cr-name"] - crNamespace := labels["codeflare.codeflare.dev/cr-namespace"] - if crName != "" { - return []reconcile.Request{ - {NamespacedName: types.NamespacedName{ - Name: crName, - Namespace: crNamespace, - }}, - } - } - } - return nil - }) - return ctrl.NewControllerManagedBy(mgr). - For(&v1alpha1.MCAD{}). - Owns(&appsv1.Deployment{}). - Owns(&corev1.ConfigMap{}). - Owns(&corev1.Service{}). - Owns(&corev1.ServiceAccount{}). - Owns(&rbacv1.RoleBinding{}). - Owns(&appsv1.Deployment{}). - Watches( - &source.Kind{Type: &rbacv1.ClusterRole{}}, - crFromLabels, - ). - Watches( - &source.Kind{Type: &rbacv1.ClusterRoleBinding{}}, - crFromLabels, - ). - Complete(r) -} - -// cleanUpClusterResources will be responsible for deleting objects that do not have owner references set -func (r *MCADReconciler) cleanUpOwnerLessResources(params *MCADParams) error { - return r.deleteOwnerLessObjects(params) -} diff --git a/controllers/mcad_controller_test.go b/controllers/mcad_controller_test.go deleted file mode 100644 index 35e892c3..00000000 --- a/controllers/mcad_controller_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package controllers - -import ( - "context" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - mfc "github.com/manifestival/controller-runtime-client" - mf "github.com/manifestival/manifestival" - - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" -) - -const ( - mcadCRCase1 = "./testdata/mcad_test_cases/case_1.yaml" - mcadConfigMap1 = "./testdata/mcad_test_results/case_1/configmap.yaml" - mcadService1 = "./testdata/mcad_test_results/case_1/service.yaml" - mcadServiceAccount1 = "./testdata/mcad_test_results/case_1/serviceaccount.yaml" - mcadCRCase2 = "./testdata/mcad_test_cases/case_2.yaml" - mcadConfigMap2 = "./testdata/mcad_test_results/case_2/configmap.yaml" - mcadService2 = "./testdata/mcad_test_results/case_2/service.yaml" - mcadServiceAccount2 = "./testdata/mcad_test_results/case_2/serviceaccount.yaml" - mcadCRCase3 = "./testdata/mcad_test_cases/case_3.yaml" - mcadDeployment3 = "./testdata/mcad_test_results/case_3/deployment.yaml" -) - -func deployMCAD(ctx context.Context, path string, opts mf.Option) { - mcad := &codeflarev1alpha1.MCAD{} - err := convertToStructuredResource(path, mcad, opts) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient.Create(ctx, mcad)).Should(Succeed()) -} - -var _ = Describe("The MCAD Controller", func() { - client := mfc.NewClient(k8sClient) - opts := mf.UseClient(client) - ctx := context.Background() - - Context("In a namespace, when a blank MCAD Custom Resource is deployed", func() { - - It("It should create a configmap", func() { - deployMCAD(ctx, mcadCRCase1, opts) - compareConfigMaps(mcadConfigMap1, opts) - compareServiceAccounts(mcadServiceAccount1, opts) - compareServices(mcadService1, opts) - }) - }) - - Context("In a namespace, when a populated MCAD Custom Resource is deployed", func() { - - It("It should create a configmap", func() { - deployMCAD(ctx, mcadCRCase2, opts) - compareConfigMaps(mcadConfigMap2, opts) - compareServiceAccounts(mcadServiceAccount2, opts) - compareServices(mcadService2, opts) - }) - }) - - Context("In a namespace, when a MCAD resource with a custom image is deployed", func() { - - It("It should create a deployment", func() { - deployMCAD(ctx, mcadCRCase3, opts) - compareDeployments(mcadDeployment3, opts) - }) - }) -}) diff --git a/controllers/mcad_params.go b/controllers/mcad_params.go deleted file mode 100644 index 5992bede..00000000 --- a/controllers/mcad_params.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2023. - -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 controllers - -import ( - mf "github.com/manifestival/manifestival" - mcadv1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" -) - -type MCADParams struct { - Name string - Namespace string - Owner mf.Owner - EnableMonitoring bool - MultiCluster bool - DispatcherMode bool - PreemptionEnabled bool - AgentConfigs string - QuotaRestURL string - PodCreationTimeout int - ControllerResources ControllerResources - ControllerImage string -} - -// ExtractParams is currently a straight-up copy. We can add in more complex validation at a later date -func (p *MCADParams) ExtractParams(mcad *mcadv1alpha1.MCAD) { - p.Name = mcad.Name - p.Namespace = mcad.Namespace - p.ControllerImage = mcad.Spec.ControllerImage - if p.ControllerImage == "" { - p.ControllerImage = MCADImage - } - p.Owner = mcad - p.EnableMonitoring = mcad.Spec.EnableMonitoring - p.MultiCluster = mcad.Spec.MultiCluster - p.DispatcherMode = mcad.Spec.DispatcherMode - p.PreemptionEnabled = mcad.Spec.PreemptionEnabled - p.AgentConfigs = mcad.Spec.AgentConfigs - p.QuotaRestURL = mcad.Spec.QuotaRestURL - p.PodCreationTimeout = mcad.Spec.PodCreationTimeout - p.ControllerResources = ControllerResources{mcad.Spec.ControllerResources} -} diff --git a/controllers/multi_cluster_app_dispatcher.go b/controllers/multi_cluster_app_dispatcher.go deleted file mode 100644 index f49d9049..00000000 --- a/controllers/multi_cluster_app_dispatcher.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2023. - -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 controllers - -import ( - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" -) - -var multiClusterAppDispatcherTemplates = []string{ - "mcad/configmap.yaml.tmpl", - "mcad/service.yaml.tmpl", - "mcad/serviceaccount.yaml.tmpl", - "mcad/deployment.yaml.tmpl", -} -var ownerLessmultiClusterAppDispatcherTemplates = []string{ - "mcad/rolebinding_custom-metrics-auth-reader.yaml.tmpl", - "mcad/clusterrole_custom-metrics-server-admin.yaml.tmpl", - "mcad/clusterrole_mcad-controller.yaml.tmpl", - "mcad/clusterrole_metrics-resource-reader.yaml.tmpl", - "mcad/clusterrolebinding_hpa-controller-custom-metrics.yaml.tmpl", - "mcad/clusterrolebinding_mcad-controller.yaml.tmpl", - "mcad/clusterrolebinding_mcad-controller-kube-scheduler.yaml.tmpl", - "mcad/clusterrolebinding_mcad-edit.yaml.tmpl", - "mcad/clusterrolebinding_mcad-system-auth-delegator.yaml.tmpl", - "mcad/clusterrolebinding_metrics-resource-reader.yaml.tmpl", -} - -func (r *MCADReconciler) ReconcileMCAD(mcad *codeflarev1alpha1.MCAD, params *MCADParams) error { - - for _, template := range multiClusterAppDispatcherTemplates { - r.Log.Info("Applying " + template) - err := r.Apply(mcad, params, template) - if err != nil { - return err - } - } - - for _, template := range ownerLessmultiClusterAppDispatcherTemplates { - r.Log.Info("Applying " + template) - err := r.ApplyWithoutOwner(params, template) - if err != nil { - return err - } - } - - r.Log.Info("Finished applying MultiClusterAppDispatcher Resources") - return nil -} - -func (r *MCADReconciler) deleteOwnerLessObjects(params *MCADParams) error { - for _, template := range ownerLessmultiClusterAppDispatcherTemplates { - r.Log.Info("Deleting Ownerless object: " + template) - err := r.DeleteResource(params, template) - if err != nil { - return err - } - } - return nil -} diff --git a/controllers/suite_test.go b/controllers/suite_test.go deleted file mode 100644 index 07442278..00000000 --- a/controllers/suite_test.go +++ /dev/null @@ -1,264 +0,0 @@ -/* -Copyright 2023. - -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 controllers - -import ( - "context" - "path/filepath" - "testing" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - mf "github.com/manifestival/manifestival" - "go.uber.org/zap/zapcore" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - "k8s.io/apimachinery/pkg/types" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/kubernetes/scheme" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "github.com/project-codeflare/codeflare-operator/controllers/util" - // +kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var ( - cfg *rest.Config - k8sClient client.Client - testEnv *envtest.Environment - ctx context.Context - cancel context.CancelFunc -) - -const ( - workingNamespace = "default" - timeout = time.Second * 30 - interval = time.Millisecond * 10 -) - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Controllers Suite") -} - -var _ = BeforeSuite(func() { - ctx, cancel = context.WithCancel(context.TODO()) - - // Initialize logger - opts := zap.Options{ - Development: true, - TimeEncoder: zapcore.TimeEncoderOfLayout(time.RFC3339), - } - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseFlagOptions(&opts))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - // Register API objects - utilruntime.Must(clientgoscheme.AddToScheme(scheme.Scheme)) - utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme)) - // +kubebuilder:scaffold:scheme - - // Initialize Kubernetes client - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - - // Setup controller manager - mgr, err := ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme.Scheme, - LeaderElection: false, - MetricsBindAddress: "0", - }) - Expect(err).NotTo(HaveOccurred()) - - err = (&MCADReconciler{ - Client: k8sClient, - Log: ctrl.Log.WithName("controllers").WithName("mcad-controller"), - Scheme: scheme.Scheme, - TemplatesPath: "../config/internal/", - }).SetupWithManager(mgr) - Expect(err).ToNot(HaveOccurred()) - - err = (&InstaScaleReconciler{ - Client: k8sClient, - Log: ctrl.Log.WithName("controllers").WithName("instascale-controller"), - Scheme: scheme.Scheme, - TemplatesPath: "../config/internal/", - }).SetupWithManager(mgr) - Expect(err).ToNot(HaveOccurred()) - - // Start the manager - go func() { - defer GinkgoRecover() - err = mgr.Start(ctx) - Expect(err).ToNot(HaveOccurred(), "Failed to run manager") - }() - -}) - -var _ = AfterSuite(func() { - // Give some time to allow workers to gracefully shutdown - time.Sleep(5 * time.Second) - cancel() - By("tearing down the test environment") - time.Sleep(1 * time.Second) - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) - -// Cleanup resources to not contaminate between tests -var _ = AfterEach(func() { - inNamespace := client.InNamespace(workingNamespace) - Expect(k8sClient.DeleteAllOf(context.TODO(), &v1alpha1.MCAD{}, inNamespace)).ToNot(HaveOccurred()) - Expect(k8sClient.DeleteAllOf(context.TODO(), &v1alpha1.InstaScale{}, inNamespace)).ToNot(HaveOccurred()) - -}) - -func convertToStructuredResource(path string, out interface{}, opts mf.Option) error { - m, err := mf.ManifestFrom(mf.Recursive(path), opts) - if err != nil { - return err - } - m, err = m.Transform(mf.InjectNamespace(workingNamespace)) - if err != nil { - return err - } - err = scheme.Scheme.Convert(&m.Resources()[0], out, nil) - if err != nil { - return err - } - return nil -} - -func compareConfigMaps(path string, opts mf.Option) { - expectedConfigMap := &corev1.ConfigMap{} - Expect(convertToStructuredResource(path, expectedConfigMap, opts)).NotTo(HaveOccurred()) - - actualConfigMap := &corev1.ConfigMap{} - Eventually(func() error { - namespacedNamed := types.NamespacedName{Name: expectedConfigMap.Name, Namespace: workingNamespace} - return k8sClient.Get(ctx, namespacedNamed, actualConfigMap) - }, timeout, interval).ShouldNot(HaveOccurred()) - - Expect(util.ConfigMapsAreEqual(*expectedConfigMap, *actualConfigMap)).Should(BeTrue()) -} - -// func compareRoleBindings(path string, opts mf.Option) { -// expectedRB := &k8srbacv1.RoleBinding{} -// Expect(convertToStructuredResource(path, expectedRB, opts)).NotTo(HaveOccurred()) -// expectedRB.Subjects[0].Namespace = workingNamespace -// -// actualRB := &k8srbacv1.RoleBinding{} -// Eventually(func() error { -// namespacedNamed := types.NamespacedName{Name: expectedRB.Name, Namespace: workingNamespace} -// return k8sClient.Get(ctx, namespacedNamed, actualRB) -// }, timeout, interval).ShouldNot(HaveOccurred()) -// -// Expect(util.RoleBindingsAreEqual(*expectedRB, *actualRB)).Should(BeTrue()) -// } - -func compareServiceAccounts(path string, opts mf.Option) { - expectedSA := &corev1.ServiceAccount{} - Expect(convertToStructuredResource(path, expectedSA, opts)).NotTo(HaveOccurred()) - expectedSA.Namespace = workingNamespace - - actualSA := &corev1.ServiceAccount{} - Eventually(func() error { - namespacedNamed := types.NamespacedName{Name: expectedSA.Name, Namespace: workingNamespace} - return k8sClient.Get(ctx, namespacedNamed, actualSA) - }, timeout, interval).ShouldNot(HaveOccurred()) - - Expect(util.ServiceAccountsAreEqual(*expectedSA, *actualSA)).Should(BeTrue()) -} - -func compareServices(path string, opts mf.Option) { - expectedService := &corev1.Service{} - Expect(convertToStructuredResource(path, expectedService, opts)).NotTo(HaveOccurred()) - - actualService := &corev1.Service{} - Eventually(func() error { - namespacedNamed := types.NamespacedName{Name: expectedService.Name, Namespace: workingNamespace} - return k8sClient.Get(ctx, namespacedNamed, actualService) - }, timeout, interval).ShouldNot(HaveOccurred()) - - Expect(util.ServicesAreEqual(*expectedService, *actualService)).Should(BeTrue()) -} - -func compareDeployments(path string, opts mf.Option) { - expectedDeployment := &appsv1.Deployment{} - Expect(convertToStructuredResource(path, expectedDeployment, opts)).NotTo(HaveOccurred()) - - actualDeployment := &appsv1.Deployment{} - Eventually(func() error { - namespacedNamed := types.NamespacedName{Name: expectedDeployment.Name, Namespace: workingNamespace} - return k8sClient.Get(ctx, namespacedNamed, actualDeployment) - }, timeout, interval).ShouldNot(HaveOccurred()) - - Expect(util.DeploymentsAreEqual(*expectedDeployment, *actualDeployment)).Should(BeTrue()) -} - -func compareClusterRoles(path string, opts mf.Option) { - expectedClusterRole := &rbacv1.ClusterRole{} - Expect(convertToStructuredResource(path, expectedClusterRole, opts)).NotTo(HaveOccurred()) - - actualClusterRole := &rbacv1.ClusterRole{} - Eventually(func() error { - namespacedNamed := types.NamespacedName{Name: expectedClusterRole.Name, Namespace: workingNamespace} - return k8sClient.Get(ctx, namespacedNamed, actualClusterRole) - }, timeout, interval).ShouldNot(HaveOccurred()) - - Expect(util.ClusterRolesAreEqual(*expectedClusterRole, *actualClusterRole)).Should(BeTrue()) -} - -func compareClusterRoleBindings(path string, opts mf.Option) { - expectedClusterRoleBinding := &rbacv1.ClusterRoleBinding{} - Expect(convertToStructuredResource(path, expectedClusterRoleBinding, opts)).NotTo(HaveOccurred()) - - actualClusterRoleBinding := &rbacv1.ClusterRoleBinding{} - Eventually(func() error { - namespacedNamed := types.NamespacedName{Name: expectedClusterRoleBinding.Name, Namespace: workingNamespace} - return k8sClient.Get(ctx, namespacedNamed, actualClusterRoleBinding) - }, timeout, interval).ShouldNot(HaveOccurred()) - - Expect(util.ClusterRoleBindingsAreEqual(*expectedClusterRoleBinding, *actualClusterRoleBinding)).Should(BeTrue()) -} diff --git a/controllers/testdata/instascale_test_cases/case_1.yaml b/controllers/testdata/instascale_test_cases/case_1.yaml deleted file mode 100644 index b63d46a8..00000000 --- a/controllers/testdata/instascale_test_cases/case_1.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: InstaScale -metadata: - name: example -spec: {} diff --git a/controllers/testdata/instascale_test_cases/case_2.yaml b/controllers/testdata/instascale_test_cases/case_2.yaml deleted file mode 100644 index 1bfaaaca..00000000 --- a/controllers/testdata/instascale_test_cases/case_2.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: InstaScale -metadata: - name: example2 -spec: - controllerResources: - limits: - cpu: '1' - memory: 1G - requests: - cpu: '1' - memory: 1G diff --git a/controllers/testdata/instascale_test_cases/case_3.yaml b/controllers/testdata/instascale_test_cases/case_3.yaml deleted file mode 100644 index a7d807f0..00000000 --- a/controllers/testdata/instascale_test_cases/case_3.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: InstaScale -metadata: - name: example-custom-image -spec: - controllerImage: quay.io/project-codeflare/instascale-controller:custom diff --git a/controllers/testdata/instascale_test_results/case_1/clusterrole.yaml b/controllers/testdata/instascale_test_results/case_1/clusterrole.yaml deleted file mode 100644 index c4053cdb..00000000 --- a/controllers/testdata/instascale_test_results/case_1/clusterrole.yaml +++ /dev/null @@ -1,68 +0,0 @@ -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: instascale-example-cr -rules: - - verbs: - - list - - watch - - get - - create - - update - - delete - - patch - apiGroups: - - '' - resources: - - nodes - - configmaps - - - verbs: - - get - apiGroups: - - '' - resourceNames: - - instascale-ocm-secret - resources: - - secrets - - - verbs: - - get - - list - apiGroups: - - config.openshift.io - resources: - - clusterversions - - - verbs: - - list - - watch - - get - apiGroups: - - apps - resources: - - deployments - - verbs: - - list - - watch - - get - - create - - update - - delete - - patch - apiGroups: - - machine.openshift.io - resources: - - '*' - - verbs: - - list - - watch - - get - - create - - update - - delete - - patch - apiGroups: - - mcad.ibm.com - resources: - - appwrappers diff --git a/controllers/testdata/instascale_test_results/case_1/clusterrolebinding.yaml b/controllers/testdata/instascale_test_results/case_1/clusterrolebinding.yaml deleted file mode 100644 index 5b0f84d9..00000000 --- a/controllers/testdata/instascale_test_results/case_1/clusterrolebinding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: instascale-example-crb -subjects: - - kind: ServiceAccount - name: instascale-example-sa - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: instascale-example-cr diff --git a/controllers/testdata/instascale_test_results/case_1/configmap.yaml b/controllers/testdata/instascale_test_results/case_1/configmap.yaml deleted file mode 100644 index a64050bd..00000000 --- a/controllers/testdata/instascale_test_results/case_1/configmap.yaml +++ /dev/null @@ -1,11 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: instascale-config - namespace: default - labels: - app: instascale-example - component: instascale -data: - maxScaleoutAllowed: '15' - useMachinePools: 'false' diff --git a/controllers/testdata/instascale_test_results/case_1/deployment.yaml b/controllers/testdata/instascale_test_results/case_1/deployment.yaml deleted file mode 100644 index 31c3896f..00000000 --- a/controllers/testdata/instascale_test_results/case_1/deployment.yaml +++ /dev/null @@ -1,30 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: instascale-example - namespace: codeflare-operator-system - labels: - app: instascale-example -spec: - replicas: 1 - selector: - matchLabels: - app: instascale-example - template: - metadata: - labels: - app: instascale-example - spec: - containers: - - name: instascale - args: - - "--configs-namespace=default" - image: quay.io/project-codeflare/instascale-controller:v0.0.4 - resources: - limits: - cpu: '2' - memory: 2G - requests: - cpu: '200m' - memory: 200M - serviceAccountName: instascale-example-sa diff --git a/controllers/testdata/instascale_test_results/case_1/serviceaccount.yaml b/controllers/testdata/instascale_test_results/case_1/serviceaccount.yaml deleted file mode 100644 index 4a7724e6..00000000 --- a/controllers/testdata/instascale_test_results/case_1/serviceaccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: ServiceAccount -apiVersion: v1 -metadata: - name: instascale-example-sa - namespace: default diff --git a/controllers/testdata/instascale_test_results/case_2/deployment.yaml b/controllers/testdata/instascale_test_results/case_2/deployment.yaml deleted file mode 100644 index eb259ec8..00000000 --- a/controllers/testdata/instascale_test_results/case_2/deployment.yaml +++ /dev/null @@ -1,30 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: instascale-example2 - namespace: codeflare-operator-system - labels: - app: instascale-example2 -spec: - replicas: 1 - selector: - matchLabels: - app: instascale-example2 - template: - metadata: - labels: - app: instascale-example2 - spec: - containers: - - name: instascale - args: - - "--configs-namespace=default" - image: quay.io/project-codeflare/instascale-controller:v0.0.4 - resources: - limits: - cpu: '1' - memory: 1G - requests: - cpu: '1' - memory: 1G - serviceAccountName: instascale-example2-sa diff --git a/controllers/testdata/instascale_test_results/case_3/deployment.yaml b/controllers/testdata/instascale_test_results/case_3/deployment.yaml deleted file mode 100644 index 0e608110..00000000 --- a/controllers/testdata/instascale_test_results/case_3/deployment.yaml +++ /dev/null @@ -1,30 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: instascale-example-custom-image - namespace: codeflare-operator-system - labels: - app: instascale-example-custom-image -spec: - replicas: 1 - selector: - matchLabels: - app: instascale-example-custom-image - template: - metadata: - labels: - app: instascale-example-custom-image - spec: - containers: - - name: instascale - args: - - "--configs-namespace=default" - image: quay.io/project-codeflare/instascale-controller:custom - resources: - limits: - cpu: '2' - memory: 2G - requests: - cpu: '200m' - memory: 200M - serviceAccountName: instascale-example-custom-image-sa diff --git a/controllers/testdata/mcad_test_cases/case_1.yaml b/controllers/testdata/mcad_test_cases/case_1.yaml deleted file mode 100644 index ac338a4c..00000000 --- a/controllers/testdata/mcad_test_cases/case_1.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: MCAD -metadata: - name: blank-custom-resource -spec: {} diff --git a/controllers/testdata/mcad_test_cases/case_2.yaml b/controllers/testdata/mcad_test_cases/case_2.yaml deleted file mode 100644 index 75b5037e..00000000 --- a/controllers/testdata/mcad_test_cases/case_2.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: MCAD -metadata: - name: populated-custom-resource -spec: - podCreationTimeout: 300 - quotaRestURL: 'bar.com' - agentConfigs: 'foo' - controllerResources: - limits: - cpu: '2' - memory: 2G - requests: - cpu: '2' - memory: 2G diff --git a/controllers/testdata/mcad_test_cases/case_3.yaml b/controllers/testdata/mcad_test_cases/case_3.yaml deleted file mode 100644 index c048e2e8..00000000 --- a/controllers/testdata/mcad_test_cases/case_3.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: codeflare.codeflare.dev/v1alpha1 -kind: MCAD -metadata: - name: custom-image -spec: - controllerImage: quay.io/project-codeflare/mcad-controller:custom diff --git a/controllers/testdata/mcad_test_results/case_1/configmap.yaml b/controllers/testdata/mcad_test_results/case_1/configmap.yaml deleted file mode 100644 index d14dbd0a..00000000 --- a/controllers/testdata/mcad_test_results/case_1/configmap.yaml +++ /dev/null @@ -1,11 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: mcad-blank-custom-resource-config - namespace: default - labels: - app: mcad-blank-custom-resource - component: multi-cluster-app-dispatcher -data: - DISPATCHER_MODE: 'false' - PREEMPTION: 'false' diff --git a/controllers/testdata/mcad_test_results/case_1/rolebinding.yaml b/controllers/testdata/mcad_test_results/case_1/rolebinding.yaml deleted file mode 100644 index d9205e2b..00000000 --- a/controllers/testdata/mcad_test_results/case_1/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: blank-custom-resource-custom-metrics-auth-reader - namespace: default -subjects: - - kind: ServiceAccount - name: mcad-controller-blank-custom-resource - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader diff --git a/controllers/testdata/mcad_test_results/case_1/service.yaml b/controllers/testdata/mcad_test_results/case_1/service.yaml deleted file mode 100644 index 6b6b57e7..00000000 --- a/controllers/testdata/mcad_test_results/case_1/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: mcad-blank-custom-resource-metrics - namespace: default -spec: - clusterIP: 172.31.181.101 - ipFamilies: - - IPv4 - ports: - - name: https - protocol: TCP - port: 443 - targetPort: 6443 - - name: http - protocol: TCP - port: 80 - targetPort: 8080 - internalTrafficPolicy: Cluster - clusterIPs: - - 172.31.181.101 - type: ClusterIP - ipFamilyPolicy: SingleStack - sessionAffinity: None - selector: - app: mcad-blank-custom-resource diff --git a/controllers/testdata/mcad_test_results/case_1/serviceaccount.yaml b/controllers/testdata/mcad_test_results/case_1/serviceaccount.yaml deleted file mode 100644 index 56786f25..00000000 --- a/controllers/testdata/mcad_test_results/case_1/serviceaccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: ServiceAccount -apiVersion: v1 -metadata: - name: mcad-controller-blank-custom-resource - namespace: default diff --git a/controllers/testdata/mcad_test_results/case_2/configmap.yaml b/controllers/testdata/mcad_test_results/case_2/configmap.yaml deleted file mode 100644 index e8aa40a9..00000000 --- a/controllers/testdata/mcad_test_results/case_2/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: mcad-populated-custom-resource-config - namespace: default - labels: - app: mcad-populated-custom-resource - component: multi-cluster-app-dispatcher -data: - DISPATCHER_MODE: 'false' - PREEMPTION: 'false' - DISPATCHER_AGENT_CONFIGS: 'foo' - DISPATCH_RESOURCE_RESERVATION_TIMEOUT: '300' - QUOTA_REST_URL: 'bar.com' diff --git a/controllers/testdata/mcad_test_results/case_2/rolebinding.yaml b/controllers/testdata/mcad_test_results/case_2/rolebinding.yaml deleted file mode 100644 index 521a11b2..00000000 --- a/controllers/testdata/mcad_test_results/case_2/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: populated-custom-resource-custom-metrics-auth-reader - namespace: default -subjects: - - kind: ServiceAccount - name: mcad-controller-populated-custom-resource - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: extension-apiserver-authentication-reader diff --git a/controllers/testdata/mcad_test_results/case_2/service.yaml b/controllers/testdata/mcad_test_results/case_2/service.yaml deleted file mode 100644 index 7f2d1d2b..00000000 --- a/controllers/testdata/mcad_test_results/case_2/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: mcad-populated-custom-resource-metrics - namespace: default -spec: - clusterIP: 172.31.181.101 - ipFamilies: - - IPv4 - ports: - - name: https - protocol: TCP - port: 443 - targetPort: 6443 - - name: http - protocol: TCP - port: 80 - targetPort: 8080 - internalTrafficPolicy: Cluster - clusterIPs: - - 172.31.181.101 - type: ClusterIP - ipFamilyPolicy: SingleStack - sessionAffinity: None - selector: - app: mcad-populated-custom-resource diff --git a/controllers/testdata/mcad_test_results/case_2/serviceaccount.yaml b/controllers/testdata/mcad_test_results/case_2/serviceaccount.yaml deleted file mode 100644 index f2003528..00000000 --- a/controllers/testdata/mcad_test_results/case_2/serviceaccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: ServiceAccount -apiVersion: v1 -metadata: - name: mcad-controller-populated-custom-resource - namespace: default diff --git a/controllers/testdata/mcad_test_results/case_3/deployment.yaml b/controllers/testdata/mcad_test_results/case_3/deployment.yaml deleted file mode 100644 index 5efa0df2..00000000 --- a/controllers/testdata/mcad_test_results/case_3/deployment.yaml +++ /dev/null @@ -1,45 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: mcad-controller-custom-image - namespace: default - labels: - app: mcad-custom-image - component: multi-cluster-application-dispatcher -spec: - replicas: 1 - selector: - matchLabels: - app: mcad-custom-image - template: - metadata: - labels: - app: mcad-custom-image - component: multi-cluster-application-dispatcher - spec: - containers: - - name: mcad-controller - args: ["--v", "4", "--logtostderr"] - command: - - mcad-controller - envFrom: - - configMapRef: - name: mcad-custom-image-config - image: quay.io/project-codeflare/mcad-controller:custom - imagePullPolicy: Always - ports: - - name: https - containerPort: 6443 - protocol: TCP - - name: http - containerPort: 8080 - protocol: TCP - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - name: temp-vol - mountPath: /tmp - serviceAccountName: mcad-controller-custom-image - volumes: - - name: temp-vol - emptyDir: {} diff --git a/controllers/util/util.go b/controllers/util/util.go deleted file mode 100644 index 00edb3ab..00000000 --- a/controllers/util/util.go +++ /dev/null @@ -1,183 +0,0 @@ -package util - -import ( - "fmt" - "reflect" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" -) - -func notEqualMsg(value string) { - print(fmt.Sprintf("%s are not equal.", value)) -} - -func ConfigMapsAreEqual(expected corev1.ConfigMap, actual corev1.ConfigMap) bool { - if expected.Name != actual.Name { - notEqualMsg("Configmap Names") - return false - } - - if !reflect.DeepEqual(expected.Data, actual.Data) { - notEqualMsg("Configmap Data values") - return false - } - return true -} - -//func RoleBindingsAreEqual(rb1 k8srbacv1.RoleBinding, rb2 k8srbacv1.RoleBinding) bool { -// -// if !reflect.DeepEqual(rb1.ObjectMeta.Labels, rb2.ObjectMeta.Labels) { -// notEqualMsg("Rolebinding labels") -// return false -// } -// if !reflect.DeepEqual(rb1.Subjects, rb2.Subjects) { -// notEqualMsg("Rolebinding subjects") -// return false -// } -// if !reflect.DeepEqual(rb1.RoleRef, rb2.RoleRef) { -// notEqualMsg("Rolebinding role references") -// return false -// } -// return true -//} - -func ServiceAccountsAreEqual(sa1 corev1.ServiceAccount, sa2 corev1.ServiceAccount) bool { - if !reflect.DeepEqual(sa1.ObjectMeta.Labels, sa2.ObjectMeta.Labels) { - notEqualMsg("ServiceAccount labels") - return false - } - if !reflect.DeepEqual(sa1.Name, sa2.Name) { - notEqualMsg("ServiceAccount names") - return false - } - if !reflect.DeepEqual(sa1.Namespace, sa2.Namespace) { - notEqualMsg("ServiceAccount namespaces") - return false - } - return true -} - -func ServicesAreEqual(service1 corev1.Service, service2 corev1.Service) bool { - if !reflect.DeepEqual(service1.ObjectMeta.Labels, service2.ObjectMeta.Labels) { - notEqualMsg("Service labels") - return false - } - if !reflect.DeepEqual(service1.Name, service2.Name) { - notEqualMsg("Service Names") - return false - } - if !reflect.DeepEqual(service1.Namespace, service2.Namespace) { - notEqualMsg("Service namespaces") - return false - } - if !reflect.DeepEqual(service1.Spec.Selector, service2.Spec.Selector) { - notEqualMsg("Service Selectors") - return false - } - if !reflect.DeepEqual(service1.Spec.Ports, service2.Spec.Ports) { - notEqualMsg("Service Ports") - return false - } - return true -} - -func DeploymentsAreEqual(dp1 appsv1.Deployment, dp2 appsv1.Deployment) bool { - - if !reflect.DeepEqual(dp1.ObjectMeta.Labels, dp2.ObjectMeta.Labels) { - notEqualMsg("labels") - return false - } - - if !reflect.DeepEqual(dp1.Spec.Selector, dp2.Spec.Selector) { - notEqualMsg("selector") - return false - } - - if !reflect.DeepEqual(dp1.Spec.Template.ObjectMeta, dp2.Spec.Template.ObjectMeta) { - notEqualMsg("Object MetaData") - return false - } - - if !reflect.DeepEqual(dp1.Spec.Template.Spec.Volumes, dp2.Spec.Template.Spec.Volumes) { - notEqualMsg("Volumes") - return false - } - - if len(dp1.Spec.Template.Spec.Containers) != len(dp2.Spec.Template.Spec.Containers) { - notEqualMsg("Containers") - return false - } - for i := range dp1.Spec.Template.Spec.Containers { - c1 := dp1.Spec.Template.Spec.Containers[i] - c2 := dp2.Spec.Template.Spec.Containers[i] - if !reflect.DeepEqual(c1.Env, c2.Env) { - notEqualMsg("Container Env") - return false - } - if !reflect.DeepEqual(c1.Ports, c2.Ports) { - notEqualMsg("Container Ports") - return false - } - if !reflect.DeepEqual(c1.Resources, c2.Resources) { - notEqualMsg("Container Resources") - return false - } - if !reflect.DeepEqual(c1.VolumeMounts, c2.VolumeMounts) { - notEqualMsg("Container VolumeMounts") - return false - } - if !reflect.DeepEqual(c1.Args, c2.Args) { - notEqualMsg("Container Args") - return false - } - if c1.Name != c2.Name { - notEqualMsg("Container Name") - return false - } - if c1.Image != c2.Image { - notEqualMsg("Container Image") - return false - } - } - - return true -} - -func ClusterRolesAreEqual(cr1 rbacv1.ClusterRole, cr2 rbacv1.ClusterRole) bool { - if !reflect.DeepEqual(cr1.Rules, cr2.Rules) { - notEqualMsg("rules") - return false - } - if !reflect.DeepEqual(cr1.ObjectMeta.Name, cr2.ObjectMeta.Name) { - notEqualMsg("name") - return false - } - return true -} - -func ClusterRoleBindingsAreEqual(crb1 rbacv1.ClusterRoleBinding, crb2 rbacv1.ClusterRoleBinding) bool { - if !reflect.DeepEqual(crb1.Subjects, crb2.Subjects) { - notEqualMsg("subjects") - return false - } - if !reflect.DeepEqual(crb1.RoleRef, crb2.RoleRef) { - notEqualMsg("roleRef") - return false - } - if !reflect.DeepEqual(crb1.ObjectMeta.Name, crb2.ObjectMeta.Name) { - notEqualMsg("name") - return false - } - return true -} - -func IsDeploymentReady(deployment *appsv1.Deployment) bool { - for _, condition := range deployment.Status.Conditions { - if condition.Type == appsv1.DeploymentAvailable && condition.Status == corev1.ConditionTrue { - return true - } - } - return false -} diff --git a/go.mod b/go.mod index b898acde..f8a0da50 100644 --- a/go.mod +++ b/go.mod @@ -1,76 +1,99 @@ module github.com/project-codeflare/codeflare-operator -go 1.18 +go 1.20 require ( - github.com/go-logr/logr v1.2.4 - github.com/manifestival/controller-runtime-client v0.4.0 - github.com/manifestival/manifestival v0.7.2 - github.com/onsi/ginkgo/v2 v2.9.2 - github.com/onsi/gomega v1.27.6 - go.uber.org/zap v1.24.0 - k8s.io/api v0.26.3 - k8s.io/apimachinery v0.26.3 - k8s.io/client-go v0.26.3 - sigs.k8s.io/controller-runtime v0.14.6 - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 + github.com/onsi/ginkgo/v2 v2.12.1 + github.com/onsi/gomega v1.27.10 + github.com/open-policy-agent/cert-controller v0.10.1 + github.com/opendatahub-io/opendatahub-operator/v2 v2.10.0 + github.com/openshift/api v0.0.0-20230823114715-5fdd7511b790 + github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c + github.com/project-codeflare/codeflare-common v0.0.0-20240207083912-d7a229270a0a + github.com/ray-project/kuberay/ray-operator v1.1.0 + go.uber.org/zap v1.26.0 + k8s.io/api v0.28.4 + k8s.io/apimachinery v0.28.4 + k8s.io/client-go v11.0.0+incompatible + k8s.io/component-base v0.28.4 + k8s.io/klog/v2 v2.100.1 + k8s.io/utils v0.0.0-20230726121419-3b25d923346b + sigs.k8s.io/controller-runtime v0.16.3 + sigs.k8s.io/yaml v1.3.0 ) +replace k8s.io/client-go => k8s.io/client-go v0.28.3 + +replace sigs.k8s.io/custom-metrics-apiserver => sigs.k8s.io/custom-metrics-apiserver v1.25.1-0.20230306170449-63d8c93851f3 + +replace go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 + +replace github.com/jackc/pgx/v4 => github.com/jackc/pgx/v5 v5.5.4 + require ( + github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/zapr v1.2.3 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect - github.com/google/uuid v1.1.2 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/gorilla/css v1.0.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jackc/pgx/v5 v5.5.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.6 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/microcosm-cc/bluemonday v1.0.18 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/openshift-online/ocm-sdk-go v0.1.411 // indirect + github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/project-codeflare/multi-cluster-app-dispatcher v1.37.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/spf13/pflag v1.0.5 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.7.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + golang.org/x/tools v0.13.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.26.1 // indirect - k8s.io/component-base v0.26.2 // indirect - k8s.io/klog/v2 v2.80.1 // indirect - k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect - k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + k8s.io/apiextensions-apiserver v0.28.4 // indirect + k8s.io/kube-openapi v0.0.0-20230901164831-6c774f458599 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect ) diff --git a/go.sum b/go.sum index 672bbaba..10d47e58 100644 --- a/go.sum +++ b/go.sum @@ -1,253 +1,84 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= -github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= -github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -255,606 +86,282 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/itchyny/gojq v0.12.7 h1:hYPTpeWfrJ1OT+2j6cvBScbhl0TkdwGM4bc66onUSOQ= +github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/manifestival/controller-runtime-client v0.4.0 h1:AK+nTZ1rhPTfAc3upnSe3TiOvAWuRmxi1vjEr55dSUM= -github.com/manifestival/controller-runtime-client v0.4.0/go.mod h1:DrsviSegfdlpVsynTUZonKE5gFkMQupenlzVmDbC6S0= -github.com/manifestival/manifestival v0.6.0/go.mod h1:3Qq9cnPy7sv7FVhg2Kvw0ebb35R4OdctS4UjTjHlHm4= -github.com/manifestival/manifestival v0.7.2 h1:l4uFdWX/xQK4QcRfqGoMtBvaZeWPEuwD6hVsCwUqZY4= -github.com/manifestival/manifestival v0.7.2/go.mod h1:nl3T6HlfHCeidooWVTMI9vYNTBkQ1GdhLNb+smozbdk= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo= +github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA= +github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/open-policy-agent/cert-controller v0.10.1 h1:RXSYoyn8FdCenWecRP//UV5nbVfmstNpj4kHQFkvPK4= +github.com/open-policy-agent/cert-controller v0.10.1/go.mod h1:4uRbBLY5DsPOog+a9pqk3JLxuuhrWsbUedQW65HcLTI= +github.com/open-policy-agent/frameworks/constraint v0.0.0-20230822235116-f0b62fe1e4c4 h1:5dum5SLEz+95JDLkMls7Z7IDPjvSq3UhJSFe4f5einQ= +github.com/opendatahub-io/opendatahub-operator/v2 v2.10.0 h1:tOX6R3N41pdyC+E1TeLErVY7KJV0zg9GAd/Z7xLT7no= +github.com/opendatahub-io/opendatahub-operator/v2 v2.10.0/go.mod h1:Hgy6bUPl29drwjs9F/5PZHUopOOojQpAPv1mWh3jnJQ= +github.com/openshift-online/ocm-sdk-go v0.1.411 h1:DlNHC3yqmk77Wzc+YJBsd0ccHXn7JFwGC1C1NOp/faw= +github.com/openshift-online/ocm-sdk-go v0.1.411/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y= +github.com/openshift/api v0.0.0-20230823114715-5fdd7511b790 h1:e3zIxk67/kiABxGFfFVECqJ4FcQRG5DPF8lgDV9f+MM= +github.com/openshift/api v0.0.0-20230823114715-5fdd7511b790/go.mod h1:yimSGmjsI+XF1mr+AKBs2//fSXIOhhetHGbMlBEfXbs= +github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c h1:CV76yFOTXmq9VciBR3Bve5ZWzSxdft7gaMVB3kS0rwg= +github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c/go.mod h1:lFMO8mLHXWFzSdYvGNo8ivF9SfF6zInA8ZGw4phRnUE= +github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= +github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/project-codeflare/codeflare-common v0.0.0-20240207083912-d7a229270a0a h1:Yk9J5qXjp+yfSRCzS0EElrhpTgfYJ+S+W/z84cmlmX4= +github.com/project-codeflare/codeflare-common v0.0.0-20240207083912-d7a229270a0a/go.mod h1:2Ck9LC+6Xi4jTDSlCJoP00tCzSrxek0roLsjvUgL2gY= +github.com/project-codeflare/multi-cluster-app-dispatcher v1.37.0 h1:oyhdLdc4BgA4zcH1zlRrSrYpzuVxV5QLDbyIXrwnQqs= +github.com/project-codeflare/multi-cluster-app-dispatcher v1.37.0/go.mod h1:Yge6GRNpO9YIDfeL+XOcCE9xbmfCTD5C1h5dlW87mxQ= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= +github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/ray-project/kuberay/ray-operator v1.1.0 h1:kCbPZG6SDv11A1F1VR0oG1oCTjrKUuZiMDsyJqmNr3g= +github.com/ray-project/kuberay/ray-operator v1.1.0/go.mod h1:ZqyKKvMP5nKDldQoKmur+Wcx7wVlV9Q98phFqHzr+KY= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200219183655-46282727080f/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -864,32 +371,24 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -897,81 +396,50 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.15.7/go.mod h1:a/tUxscL+UxvYyA7Tj5DRc8ivYqJIO1Y5KDdlI6wSvo= -k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= -k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= -k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= -k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= -k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg= -k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI= -k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM= -k8s.io/apimachinery v0.15.7/go.mod h1:Xc10RHc1U+F/e9GCloJ8QAeCGevSVP5xhOhqlE+e1kM= -k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.19.7/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q= -k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= -k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= -k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= -k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= -k8s.io/client-go v0.15.7/go.mod h1:QMNB76d3lKPvPQdOOnnxUF693C3hnCzUbC2umg70pWA= -k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= -k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= -k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s= -k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ= -k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= -k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= -k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI= -k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ= +k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= +k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/apiextensions-apiserver v0.28.4 h1:AZpKY/7wQ8n+ZYDtNHbAJBb+N4AXXJvyZx6ww6yAJvU= +k8s.io/apiextensions-apiserver v0.28.4/go.mod h1:pgQIZ1U8eJSMQcENew/0ShUTlePcSGFq6dxSxf2mwPM= +k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= +k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= +k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= +k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/component-base v0.28.4 h1:c/iQLWPdUgI90O+T9TeECg8o7N3YJTiuz2sKxILYcYo= +k8s.io/component-base v0.28.4/go.mod h1:m9hR0uvqXDybiGL2nf/3Lf0MerAfQXzkfWhUY58JUbU= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20200204173128-addea2498afe/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= -k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= -k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= -sigs.k8s.io/controller-runtime v0.7.2/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= -sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA= -sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-aggregator v0.28.3 h1:CVbj3+cpshSHR5dWPzLYx3sVpIDEPLlzMSxY/lAc9cM= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20230901164831-6c774f458599 h1:nVKRi5eItf3x9kkIMfdT4D1/LqPzj0bLjxLYWbdUtV0= +k8s.io/kube-openapi v0.0.0-20230901164831-6c774f458599/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= +sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= +sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/hack/tools.go b/hack/tools.go new file mode 100644 index 00000000..f28d1037 --- /dev/null +++ b/hack/tools.go @@ -0,0 +1,4 @@ +//go:build tools +// +build tools + +package hack diff --git a/hack/verify-imports.sh b/hack/verify-imports.sh new file mode 100755 index 00000000..b823a84b --- /dev/null +++ b/hack/verify-imports.sh @@ -0,0 +1,13 @@ +#!/bin/bash +OPENSHIFT_GOIMPORTS=${1} + +# ${OPENSHIFT_GOIMPORTS} -l +bad_files=$(${OPENSHIFT_GOIMPORTS} -l) + +echo $bad_files +if [[ -n ${bad_files} ]]; then + echo "!!! openshift-goimports needs to be run on the following files:" + echo "${bad_files}" + echo "Try running 'make imports'" + exit 1 +fi diff --git a/main.go b/main.go index 5358e04b..31afbcbb 100644 --- a/main.go +++ b/main.go @@ -17,105 +17,346 @@ limitations under the License. package main import ( + "context" + "errors" "flag" + "fmt" + "net/http" "os" + "strings" "time" + cert "github.com/open-policy-agent/cert-controller/pkg/rotator" + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" "go.uber.org/zap/zapcore" - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - _ "k8s.io/client-go/plugin/pkg/client/auth" - + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/discovery" + "k8s.io/client-go/kubernetes" clientgoscheme "k8s.io/client-go/kubernetes/scheme" - + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/rest" + configv1alpha1 "k8s.io/component-base/config/v1alpha1" + "k8s.io/klog/v2" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/yaml" + + routev1 "github.com/openshift/api/route/v1" + clientset "github.com/openshift/client-go/config/clientset/versioned" - codeflarev1alpha1 "github.com/project-codeflare/codeflare-operator/api/codeflare/v1alpha1" - "github.com/project-codeflare/codeflare-operator/controllers" + "github.com/project-codeflare/codeflare-operator/pkg/config" + "github.com/project-codeflare/codeflare-operator/pkg/controllers" + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. // +kubebuilder:scaffold:imports ) var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") - templatesPath = "config/internal/" + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") + OperatorVersion = "UNKNOWN" + BuildDate = "UNKNOWN" ) func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - - utilruntime.Must(codeflarev1alpha1.AddToScheme(scheme)) - // +kubebuilder:scaffold:scheme + // Ray + utilruntime.Must(rayv1.AddToScheme(scheme)) + // OpenShift Route + utilruntime.Must(routev1.Install(scheme)) + // ODH + utilruntime.Must(dsciv1.AddToScheme(scheme)) } +// +kubebuilder:rbac:groups=config.openshift.io,resources=ingresses,verbs=get + func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - opts := zap.Options{ + var configMapName string + flag.StringVar(&configMapName, "config", "codeflare-operator-config", + "The name of the ConfigMap to load the operator configuration from. "+ + "If it does not exist, the operator will create and initialise it.") + + zapOptions := zap.Options{ Development: true, TimeEncoder: zapcore.TimeEncoderOfLayout(time.RFC3339), } - opts.BindFlags(flag.CommandLine) + zapOptions.BindFlags(flag.CommandLine) flag.Parse() - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&zapOptions))) + klog.SetLogger(ctrl.Log) + + setupLog.Info("Build info", + "operatorVersion", OperatorVersion, + "date", BuildDate, + ) + + ctx := ctrl.SetupSignalHandler() + + cfg := &config.CodeFlareOperatorConfiguration{ + ClientConnection: &config.ClientConnection{ + QPS: ptr.To(float32(50)), + Burst: ptr.To(int32(100)), + }, + ControllerManager: config.ControllerManager{ + Metrics: config.MetricsConfiguration{ + BindAddress: ":8080", + }, + Health: config.HealthConfiguration{ + BindAddress: ":8081", + ReadinessEndpointName: "readyz", + LivenessEndpointName: "healthz", + }, + LeaderElection: &configv1alpha1.LeaderElectionConfiguration{}, + }, + KubeRay: &config.KubeRayConfiguration{ + RayDashboardOAuthEnabled: ptr.To(true), + IngressDomain: "", + MTLSEnabled: ptr.To(true), + }, + } + + kubeConfig, err := ctrl.GetConfig() + exitOnError(err, "unable to get client config") + if kubeConfig.UserAgent == "" { + kubeConfig.UserAgent = "codeflare-operator" + } + kubeClient, err := kubernetes.NewForConfig(kubeConfig) + exitOnError(err, "unable to create Kubernetes client") + + namespace := namespaceOrDie() + + exitOnError(loadIntoOrCreate(ctx, kubeClient, namespace, configMapName, cfg), "unable to initialise configuration") - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: metricsAddr, - Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "5a3ca514.codeflare.dev", + kubeConfig.Burst = int(ptr.Deref(cfg.ClientConnection.Burst, int32(rest.DefaultBurst))) + kubeConfig.QPS = ptr.Deref(cfg.ClientConnection.QPS, rest.DefaultQPS) + setupLog.V(2).Info("REST client", "qps", kubeConfig.QPS, "burst", kubeConfig.Burst) + + mgr, err := ctrl.NewManager(kubeConfig, ctrl.Options{ + Scheme: scheme, + Metrics: metricsserver.Options{ + BindAddress: cfg.Metrics.BindAddress, + }, + HealthProbeBindAddress: cfg.Health.BindAddress, + LeaderElection: ptr.Deref(cfg.LeaderElection.LeaderElect, false), + LeaderElectionID: cfg.LeaderElection.ResourceName, + LeaderElectionNamespace: cfg.LeaderElection.ResourceNamespace, + LeaderElectionResourceLock: cfg.LeaderElection.ResourceLock, + LeaseDuration: &cfg.LeaderElection.LeaseDuration.Duration, + RetryPeriod: &cfg.LeaderElection.RetryPeriod.Duration, + RenewDeadline: &cfg.LeaderElection.RenewDeadline.Duration, + }) + exitOnError(err, "unable to create manager") + + certsReady := make(chan struct{}) + exitOnError(setupCertManagement(mgr, namespace, certsReady), "unable to setup cert-controller") + + if cfg.KubeRay.IngressDomain == "" { + configClient, err := clientset.NewForConfig(kubeConfig) + exitOnError(err, "unable to create Route Client Set") + cfg.KubeRay.IngressDomain, err = getClusterDomain(ctx, configClient) + exitOnError(err, cfg.KubeRay.IngressDomain) + } + + go setupControllers(mgr, kubeClient, cfg, isOpenShift(ctx, kubeClient.DiscoveryClient), certsReady) + + setupLog.Info("setting up health endpoints") + exitOnError(setupProbeEndpoints(mgr, cfg, certsReady), "unable to set up health check") + + setupLog.Info("starting manager") + exitOnError(mgr.Start(ctx), "error running manager") +} + +func setupControllers(mgr ctrl.Manager, dc discovery.DiscoveryInterface, cfg *config.CodeFlareOperatorConfiguration, isOpenShift bool, certsReady chan struct{}) { + setupLog.Info("Waiting for certificate generation to complete") + <-certsReady + setupLog.Info("Certs ready") + + exitOnError(controllers.SetupRayClusterWebhookWithManager(mgr, cfg.KubeRay), "error setting up RayCluster webhook") + + ok, err := hasAPIResourceForGVK(dc, rayv1.GroupVersion.WithKind("RayCluster")) + if ok { + rayClusterController := controllers.RayClusterReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Config: cfg.KubeRay, + IsOpenShift: isOpenShift, + } + exitOnError(rayClusterController.SetupWithManager(mgr), "Error setting up RayCluster controller") + } else if err != nil { + exitOnError(err, "Could not determine if RayCluster CR present on cluster.") + } +} + +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;update +// +kubebuilder:rbac:groups="admissionregistration.k8s.io",resources=mutatingwebhookconfigurations,verbs=get;list;watch;update +// +kubebuilder:rbac:groups="admissionregistration.k8s.io",resources=validatingwebhookconfigurations,verbs=get;list;watch;update + +func setupCertManagement(mgr ctrl.Manager, namespace string, certsReady chan struct{}) error { + return cert.AddRotator(mgr, &cert.CertRotator{ + SecretKey: types.NamespacedName{ + Namespace: namespace, + Name: "codeflare-operator-webhook-server-cert", + }, + CertDir: "/tmp/k8s-webhook-server/serving-certs", + CAName: "codeflare", + CAOrganization: "openshift.ai", + DNSName: fmt.Sprintf("%s.%s.svc", "codeflare-operator-webhook-service", namespace), + IsReady: certsReady, + Webhooks: []cert.WebhookInfo{ + { + Type: cert.Validating, + Name: "codeflare-operator-validating-webhook-configuration", + }, + { + Type: cert.Mutating, + Name: "codeflare-operator-mutating-webhook-configuration", + }, + }, + // When the controller is running in the leader election mode, + // we expect webhook server will run in primary and secondary instance + RequireLeaderElection: false, }) +} + +func setupProbeEndpoints(mgr ctrl.Manager, cfg *config.CodeFlareOperatorConfiguration, certsReady chan struct{}) error { + err := mgr.AddHealthzCheck(cfg.Health.LivenessEndpointName, healthz.Ping) if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) + return err } - if err = (&controllers.MCADReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Log: ctrl.Log, - TemplatesPath: templatesPath, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "MCAD") - os.Exit(1) + return mgr.AddReadyzCheck(cfg.Health.ReadinessEndpointName, func(req *http.Request) error { + select { + case <-certsReady: + return mgr.GetWebhookServer().StartedChecker()(req) + default: + return errors.New("certificates are not ready") + } + }) +} + +func loadIntoOrCreate(ctx context.Context, client kubernetes.Interface, ns, name string, cfg *config.CodeFlareOperatorConfiguration) error { + configMap, err := client.CoreV1().ConfigMaps(ns).Get(ctx, name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return createConfigMap(ctx, client, ns, name, cfg) + } else if err != nil { + return err } - if err = (&controllers.InstaScaleReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Log: ctrl.Log, - TemplatesPath: templatesPath, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "InstaScale") - os.Exit(1) + + if len(configMap.Data) != 1 { + return fmt.Errorf("cannot resolve config from ConfigMap %s/%s", configMap.Namespace, configMap.Name) } - // +kubebuilder:scaffold:builder - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) + for _, data := range configMap.Data { + return yaml.Unmarshal([]byte(data), cfg) } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") - os.Exit(1) + + return nil +} + +func createConfigMap(ctx context.Context, client kubernetes.Interface, ns, name string, cfg *config.CodeFlareOperatorConfiguration) error { + content, err := yaml.Marshal(cfg) + if err != nil { + return err } - setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running manager") + configMap := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Data: map[string]string{ + "config.yaml": string(content), + }, + } + + _, err = client.CoreV1().ConfigMaps(ns).Create(ctx, configMap, metav1.CreateOptions{}) + return err +} + +func hasAPIResourceForGVK(dc discovery.DiscoveryInterface, gvk schema.GroupVersionKind) (bool, error) { + gv, kind := gvk.ToAPIVersionAndKind() + if resources, err := dc.ServerResourcesForGroupVersion(gv); err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } else { + for _, res := range resources.APIResources { + if res.Kind == kind { + return true, nil + } + } + } + return false, nil +} + +func namespaceOrDie() string { + // This way assumes you've set the NAMESPACE environment variable either manually, when running + // the operator standalone, or using the downward API, when running the operator in-cluster. + if ns := os.Getenv("NAMESPACE"); ns != "" { + return ns + } + + // Fall back to the namespace associated with the service account token, if available + if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if ns := strings.TrimSpace(string(data)); len(ns) > 0 { + return ns + } + } + + panic("unable to determine current namespace") +} + +func exitOnError(err error, msg string) { + if err != nil { + setupLog.Error(err, msg) os.Exit(1) } } + +func isOpenShift(ctx context.Context, dc discovery.DiscoveryInterface) bool { + logger := ctrl.LoggerFrom(ctx) + apiGroupList, err := dc.ServerGroups() + if err != nil { + logger.Info("Error while querying ServerGroups, assuming we're on Vanilla Kubernetes") + return false + } + for i := 0; i < len(apiGroupList.Groups); i++ { + if strings.HasSuffix(apiGroupList.Groups[i].Name, ".openshift.io") { + logger.Info("We detected being on OpenShift!") + return true + } + } + logger.Info("We detected being on Vanilla Kubernetes!") + return false +} + +func getClusterDomain(ctx context.Context, configClient *clientset.Clientset) (string, error) { + ingress, err := configClient.ConfigV1().Ingresses().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return "", fmt.Errorf("failed to get Ingress object: %v", err) + } + + domain := ingress.Spec.Domain + if domain == "" { + return "", fmt.Errorf("domain is not set in the Ingress object") + } + + return domain, nil +} diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 00000000..af3bc349 --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,89 @@ +/* +Copyright 2023. + +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 config + +import ( + configv1alpha1 "k8s.io/component-base/config/v1alpha1" +) + +type CodeFlareOperatorConfiguration struct { + // ClientConnection provides additional configuration options for Kubernetes + // API server client. + ClientConnection *ClientConnection `json:"clientConnection,omitempty"` + + // ControllerManager returns the configurations for controllers + ControllerManager `json:",inline"` + + KubeRay *KubeRayConfiguration `json:"kuberay,omitempty"` +} + +type KubeRayConfiguration struct { + RayDashboardOAuthEnabled *bool `json:"rayDashboardOAuthEnabled,omitempty"` + + IngressDomain string `json:"ingressDomain"` + + MTLSEnabled *bool `json:"mTLSEnabled,omitempty"` +} + +type ControllerManager struct { + // Metrics contains the controller metrics configuration + // +optional + Metrics MetricsConfiguration `json:"metrics,omitempty"` + + // Health contains the controller health configuration + // +optional + Health HealthConfiguration `json:"health,omitempty"` + + // LeaderElection is the LeaderElection config to be used when configuring + // the manager.Manager leader election + LeaderElection *configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"` +} + +type ClientConnection struct { + // QPS controls the number of queries per second allowed before client-side throttling + // connection to the API server. + QPS *float32 `json:"qps,omitempty"` + + // Burst allows extra queries to accumulate when a client is exceeding its rate. + Burst *int32 `json:"burst,omitempty"` +} + +// MetricsConfiguration defines the metrics configuration. +type MetricsConfiguration struct { + // BindAddress is the TCP address that the controller should bind to + // for serving Prometheus metrics. + // It can be set to "0" to disable the metrics serving. + // +optional + BindAddress string `json:"bindAddress,omitempty"` +} + +// HealthConfiguration defines the health configuration. +type HealthConfiguration struct { + // BindAddress is the TCP address that the controller should bind to + // for serving health probes. + // It can be set to "0" or "" to disable serving the health probe. + // +optional + BindAddress string `json:"bindAddress,omitempty"` + + // ReadinessEndpointName, defaults to "readyz" + // +optional + ReadinessEndpointName string `json:"readinessEndpointName,omitempty"` + + // LivenessEndpointName, defaults to "healthz" + // +optional + LivenessEndpointName string `json:"livenessEndpointName,omitempty"` +} diff --git a/pkg/controllers/raycluster_controller.go b/pkg/controllers/raycluster_controller.go new file mode 100644 index 00000000..41464af2 --- /dev/null +++ b/pkg/controllers/raycluster_controller.go @@ -0,0 +1,533 @@ +/* +Copyright 2023. + +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 controllers + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "fmt" + "math/big" + rand2 "math/rand" + "time" + + dsciv1 "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" + rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + corev1ac "k8s.io/client-go/applyconfigurations/core/v1" + metav1ac "k8s.io/client-go/applyconfigurations/meta/v1" + networkingv1ac "k8s.io/client-go/applyconfigurations/networking/v1" + rbacv1ac "k8s.io/client-go/applyconfigurations/rbac/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + routev1 "github.com/openshift/api/route/v1" + routev1ac "github.com/openshift/client-go/route/applyconfigurations/route/v1" + routev1client "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + + "github.com/project-codeflare/codeflare-operator/pkg/config" +) + +// RayClusterReconciler reconciles a RayCluster object +type RayClusterReconciler struct { + client.Client + kubeClient *kubernetes.Clientset + routeClient *routev1client.RouteV1Client + Scheme *runtime.Scheme + CookieSalt string + Config *config.KubeRayConfiguration + IsOpenShift bool +} + +const ( + requeueTime = 10 + controllerName = "codeflare-raycluster-controller" + oAuthFinalizer = "ray.openshift.ai/oauth-finalizer" + oAuthServicePort = 443 + oAuthServicePortName = "oauth-proxy" + ingressServicePortName = "dashboard" + logRequeueing = "requeueing" + + CAPrivateKeyKey = "ca.key" + CACertKey = "ca.crt" +) + +var ( + deletePolicy = metav1.DeletePropagationForeground + deleteOptions = client.DeleteOptions{PropagationPolicy: &deletePolicy} +) + +// +kubebuilder:rbac:groups=ray.io,resources=rayclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ray.io,resources=rayclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=ray.io,resources=rayclusters/finalizers,verbs=update +// +kubebuilder:rbac:groups=route.openshift.io,resources=routes;routes/custom-host,verbs=get;create;update;patch;delete +// +kubebuilder:rbac:groups=networking.k8s.io,resources=ingresses,verbs=get;create;update;patch;delete +// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;create;patch;delete;get +// +kubebuilder:rbac:groups=core,resources=services,verbs=get;create;update;patch;delete +// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;create;update;patch;delete +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=get;create;update;patch;delete +// +kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create; +// +kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create; +// +kubebuilder:rbac:groups=dscinitialization.opendatahub.io,resources=dscinitializations,verbs=get;list;watch +// +kubebuilder:rbac:groups=networking.k8s.io,resources=networkpolicies,verbs=get;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the RayCluster object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.15.3/pkg/reconcile + +func (r *RayClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := ctrl.LoggerFrom(ctx) + + cluster := &rayv1.RayCluster{} + + if err := r.Get(ctx, req.NamespacedName, cluster); err != nil { + if !errors.IsNotFound(err) { + logger.Error(err, "Error getting RayCluster resource") + } + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + if cluster.ObjectMeta.DeletionTimestamp.IsZero() { + if !controllerutil.ContainsFinalizer(cluster, oAuthFinalizer) { + logger.Info("Add a finalizer", "finalizer", oAuthFinalizer) + controllerutil.AddFinalizer(cluster, oAuthFinalizer) + if err := r.Update(ctx, cluster); err != nil { + // this log is info level since errors are not fatal and are expected + logger.Info("WARN: Failed to update RayCluster with finalizer", "error", err.Error(), logRequeueing, true) + return ctrl.Result{RequeueAfter: requeueTime}, err + } + } + } else if controllerutil.ContainsFinalizer(cluster, oAuthFinalizer) { + err := client.IgnoreNotFound(r.Client.Delete( + ctx, + &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: crbNameFromCluster(cluster), + }, + }, + &deleteOptions, + )) + if err != nil { + logger.Error(err, "Failed to remove OAuth ClusterRoleBinding.", logRequeueing, true) + return ctrl.Result{RequeueAfter: requeueTime}, err + } + controllerutil.RemoveFinalizer(cluster, oAuthFinalizer) + if err := r.Update(ctx, cluster); err != nil { + logger.Error(err, "Failed to remove finalizer from RayCluster", logRequeueing, true) + return ctrl.Result{RequeueAfter: requeueTime}, err + } + logger.Info("Successfully removed finalizer.", logRequeueing, false) + return ctrl.Result{}, nil + } + + if isMTLSEnabled(r.Config) { + caSecretName := caSecretNameFromCluster(cluster) + caSecret, err := r.kubeClient.CoreV1().Secrets(cluster.Namespace).Get(ctx, caSecretName, metav1.GetOptions{}) + if errors.IsNotFound(err) { + key, cert, err := generateCACertificate() + if err != nil { + logger.Error(err, "Failed to generate CA certificate") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + _, err = r.kubeClient.CoreV1().Secrets(cluster.Namespace).Apply(ctx, desiredCASecret(cluster, key, cert), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to apply CA Secret") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + } else if err != nil { + logger.Error(err, "Failed to get CA Secret") + return ctrl.Result{RequeueAfter: requeueTime}, err + } else { + key := caSecret.Data[CAPrivateKeyKey] + cert := caSecret.Data[CACertKey] + _, err = r.kubeClient.CoreV1().Secrets(cluster.Namespace).Apply(ctx, desiredCASecret(cluster, key, cert), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to apply CA Secret") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + } + } + + if cluster.Status.State != "suspended" && isRayDashboardOAuthEnabled(r.Config) && r.IsOpenShift { + logger.Info("Creating OAuth Objects") + _, err := r.routeClient.Routes(cluster.Namespace).Apply(ctx, desiredClusterRoute(cluster), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update OAuth Route") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + + _, err = r.kubeClient.CoreV1().Secrets(cluster.Namespace).Apply(ctx, desiredOAuthSecret(cluster, r.CookieSalt), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to create OAuth Secret") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + + _, err = r.kubeClient.CoreV1().Services(cluster.Namespace).Apply(ctx, desiredOAuthService(cluster), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update OAuth Service") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + + _, err = r.kubeClient.CoreV1().ServiceAccounts(cluster.Namespace).Apply(ctx, desiredServiceAccount(cluster), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update OAuth ServiceAccount") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + + _, err = r.kubeClient.RbacV1().ClusterRoleBindings().Apply(ctx, desiredOAuthClusterRoleBinding(cluster), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update OAuth ClusterRoleBinding") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + + logger.Info("Creating RayClient Route") + _, err = r.routeClient.Routes(cluster.Namespace).Apply(ctx, desiredRayClientRoute(cluster), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update RayClient Route") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + + } else if cluster.Status.State != "suspended" && !isRayDashboardOAuthEnabled(r.Config) && !r.IsOpenShift { + logger.Info("We detected being on Vanilla Kubernetes!") + logger.Info("Creating Dashboard Ingress") + dashboardName := dashboardNameFromCluster(cluster) + dashboardIngressHost, err := getIngressHost(r.Config, cluster, dashboardName) + if err != nil { + return ctrl.Result{RequeueAfter: requeueTime}, err + } + _, err = r.kubeClient.NetworkingV1().Ingresses(cluster.Namespace).Apply(ctx, desiredClusterIngress(cluster, dashboardIngressHost), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + // This log is info level since errors are not fatal and are expected + logger.Info("WARN: Failed to update Dashboard Ingress", "error", err.Error(), logRequeueing, true) + return ctrl.Result{RequeueAfter: requeueTime}, err + } + logger.Info("Creating RayClient Ingress") + rayClientName := rayClientNameFromCluster(cluster) + rayClientIngressHost, err := getIngressHost(r.Config, cluster, rayClientName) + if err != nil { + return ctrl.Result{RequeueAfter: requeueTime}, err + } + _, err = r.kubeClient.NetworkingV1().Ingresses(cluster.Namespace).Apply(ctx, desiredRayClientIngress(cluster, rayClientIngressHost), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update RayClient Ingress") + return ctrl.Result{RequeueAfter: requeueTime}, err + } + } + + // Locate the KubeRay operator deployment: + // - First try to get the ODH / RHOAI application namespace from the DSCInitialization + // - Or fallback to the well-known defaults + var kubeRayNamespaces []string + dsci := &dsciv1.DSCInitialization{} + err := r.Client.Get(ctx, client.ObjectKey{Name: "default-dsci"}, dsci) + if errors.IsNotFound(err) { + kubeRayNamespaces = []string{"opendatahub", "redhat-ods-applications"} + } else if err != nil { + return ctrl.Result{}, err + } else { + kubeRayNamespaces = []string{dsci.Spec.ApplicationsNamespace} + } + + _, err = r.kubeClient.NetworkingV1().NetworkPolicies(cluster.Namespace).Apply(ctx, desiredNetworkPolicy(cluster, r.Config, kubeRayNamespaces), metav1.ApplyOptions{FieldManager: controllerName, Force: true}) + if err != nil { + logger.Error(err, "Failed to update NetworkPolicy") + } + + return ctrl.Result{}, nil +} + +// getIngressHost generates the cluster URL string based on the cluster type, RayCluster, and ingress domain. +func getIngressHost(cfg *config.KubeRayConfiguration, cluster *rayv1.RayCluster, ingressNameFromCluster string) (string, error) { + ingressDomain := "" + if cfg != nil && cfg.IngressDomain != "" { + ingressDomain = cfg.IngressDomain + } else { + return "", fmt.Errorf("missing IngressDomain configuration in ConfigMap 'codeflare-operator-config'") + } + return fmt.Sprintf("%s-%s.%s", ingressNameFromCluster, cluster.Namespace, ingressDomain), nil +} + +func isRayDashboardOAuthEnabled(cfg *config.KubeRayConfiguration) bool { + return cfg == nil || ptr.Deref(cfg.RayDashboardOAuthEnabled, true) +} + +func isMTLSEnabled(cfg *config.KubeRayConfiguration) bool { + return cfg == nil || ptr.Deref(cfg.MTLSEnabled, true) +} + +func crbNameFromCluster(cluster *rayv1.RayCluster) string { + return cluster.Name + "-" + cluster.Namespace + "-auth" // NOTE: potential naming conflicts ie {name: foo, ns: bar-baz} and {name: foo-bar, ns: baz} +} + +func desiredOAuthClusterRoleBinding(cluster *rayv1.RayCluster) *rbacv1ac.ClusterRoleBindingApplyConfiguration { + return rbacv1ac.ClusterRoleBinding( + crbNameFromCluster(cluster)). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithSubjects( + rbacv1ac.Subject(). + WithKind("ServiceAccount"). + WithName(oauthServiceAccountNameFromCluster(cluster)). + WithNamespace(cluster.Namespace), + ). + WithRoleRef( + rbacv1ac.RoleRef(). + WithAPIGroup("rbac.authorization.k8s.io"). + WithKind("ClusterRole"). + WithName("system:auth-delegator"), + ) +} + +func oauthServiceAccountNameFromCluster(cluster *rayv1.RayCluster) string { + return cluster.Name + "-oauth-proxy" +} + +func desiredServiceAccount(cluster *rayv1.RayCluster) *corev1ac.ServiceAccountApplyConfiguration { + return corev1ac.ServiceAccount(oauthServiceAccountNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithAnnotations(map[string]string{ + "serviceaccounts.openshift.io/oauth-redirectreference.first": "" + + `{"kind":"OAuthRedirectReference","apiVersion":"v1",` + + `"reference":{"kind":"Route","name":"` + dashboardNameFromCluster(cluster) + `"}}`, + }). + WithOwnerReferences( + metav1ac.OwnerReference().WithUID(cluster.UID).WithName(cluster.Name).WithKind(cluster.Kind).WithAPIVersion(cluster.APIVersion), + ) +} + +func dashboardNameFromCluster(cluster *rayv1.RayCluster) string { + return "ray-dashboard-" + cluster.Name +} + +func rayClientNameFromCluster(cluster *rayv1.RayCluster) string { + return "rayclient-" + cluster.Name +} + +func desiredClusterRoute(cluster *rayv1.RayCluster) *routev1ac.RouteApplyConfiguration { + return routev1ac.Route(dashboardNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithSpec(routev1ac.RouteSpec(). + WithTo(routev1ac.RouteTargetReference().WithKind("Service").WithName(oauthServiceNameFromCluster(cluster))). + WithPort(routev1ac.RoutePort().WithTargetPort(intstr.FromString((oAuthServicePortName)))). + WithTLS(routev1ac.TLSConfig(). + WithInsecureEdgeTerminationPolicy(routev1.InsecureEdgeTerminationPolicyRedirect). + WithTermination(routev1.TLSTerminationReencrypt), + ), + ). + WithOwnerReferences( + metav1ac.OwnerReference().WithUID(cluster.UID).WithName(cluster.Name).WithKind(cluster.Kind).WithAPIVersion(cluster.APIVersion), + ) +} + +func oauthServiceNameFromCluster(cluster *rayv1.RayCluster) string { + return cluster.Name + "-oauth" +} + +func oauthServiceTLSSecretName(cluster *rayv1.RayCluster) string { + return cluster.Name + "-proxy-tls-secret" +} + +func desiredOAuthService(cluster *rayv1.RayCluster) *corev1ac.ServiceApplyConfiguration { + return corev1ac.Service(oauthServiceNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithAnnotations(map[string]string{"service.beta.openshift.io/serving-cert-secret-name": oauthServiceTLSSecretName(cluster)}). + WithSpec( + corev1ac.ServiceSpec(). + WithPorts( + corev1ac.ServicePort(). + WithName(oAuthServicePortName). + WithPort(oAuthServicePort). + WithTargetPort(intstr.FromString(oAuthServicePortName)). + WithProtocol(corev1.ProtocolTCP), + ). + WithSelector(map[string]string{"ray.io/cluster": cluster.Name, "ray.io/node-type": "head"}), + ). + WithOwnerReferences( + metav1ac.OwnerReference().WithUID(cluster.UID).WithName(cluster.Name).WithKind(cluster.Kind).WithAPIVersion(cluster.APIVersion), + ) +} + +func oauthSecretNameFromCluster(cluster *rayv1.RayCluster) string { + return cluster.Name + "-oauth-config" +} + +// desiredOAuthSecret defines the desired OAuth secret object +func desiredOAuthSecret(cluster *rayv1.RayCluster, cookieSalt string) *corev1ac.SecretApplyConfiguration { + // Generate the cookie secret for the OAuth proxy + hasher := sha1.New() // REVIEW is SHA1 okay here? + hasher.Write([]byte(cluster.Name + cookieSalt)) + cookieSecret := base64.StdEncoding.EncodeToString(hasher.Sum(nil)) + + return corev1ac.Secret(oauthSecretNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithStringData(map[string]string{"cookie_secret": cookieSecret}). + WithOwnerReferences( + metav1ac.OwnerReference().WithUID(cluster.UID).WithName(cluster.Name).WithKind(cluster.Kind).WithAPIVersion(cluster.APIVersion), + ) +} + +func caSecretNameFromCluster(cluster *rayv1.RayCluster) string { + return "ca-secret-" + cluster.Name +} + +func desiredCASecret(cluster *rayv1.RayCluster, key, cert []byte) *corev1ac.SecretApplyConfiguration { + return corev1ac.Secret(caSecretNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithData(map[string][]byte{ + CAPrivateKeyKey: key, + CACertKey: cert, + }). + WithOwnerReferences(metav1ac.OwnerReference(). + WithUID(cluster.UID). + WithName(cluster.Name). + WithKind(cluster.Kind). + WithAPIVersion(cluster.APIVersion)) +} + +func generateCACertificate() ([]byte, []byte, error) { + serialNumber := big.NewInt(rand2.Int63()) + cert := &x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: "root-ca", + }, + Issuer: pkix.Name{ + CommonName: "root-ca", + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + certPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, err + } + + privateKeyBytes := x509.MarshalPKCS1PrivateKey(certPrivateKey) + privateKeyPem := pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: privateKeyBytes, + }, + ) + certBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &certPrivateKey.PublicKey, certPrivateKey) + if err != nil { + return nil, nil, err + } + + certPem := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + }) + + return privateKeyPem, certPem, nil +} + +func desiredNetworkPolicy(cluster *rayv1.RayCluster, cfg *config.KubeRayConfiguration, kubeRayNamespaces []string) *networkingv1ac.NetworkPolicyApplyConfiguration { + allSecuredPorts := []*networkingv1ac.NetworkPolicyPortApplyConfiguration{ + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(8443)), + } + if ptr.Deref(cfg.MTLSEnabled, true) { + allSecuredPorts = append(allSecuredPorts, networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(10001))) + } + return networkingv1ac.NetworkPolicy(cluster.Name, cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithSpec(networkingv1ac.NetworkPolicySpec(). + WithPodSelector(metav1ac.LabelSelector().WithMatchLabels(map[string]string{"ray.io/cluster": cluster.Name, "ray.io/node-type": "head"})). + WithIngress( + networkingv1ac.NetworkPolicyIngressRule(). + WithPorts( + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(6379)), + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(10001)), + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(8080)), + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(8265)), + ).WithFrom( + networkingv1ac.NetworkPolicyPeer().WithPodSelector(metav1ac.LabelSelector()), + ), + networkingv1ac.NetworkPolicyIngressRule(). + WithFrom( + networkingv1ac.NetworkPolicyPeer().WithPodSelector(metav1ac.LabelSelector(). + WithMatchLabels(map[string]string{"app.kubernetes.io/component": "kuberay-operator"})). + WithNamespaceSelector(metav1ac.LabelSelector(). + WithMatchExpressions(metav1ac.LabelSelectorRequirement(). + WithKey(corev1.LabelMetadataName). + WithOperator(metav1.LabelSelectorOpIn). + WithValues(kubeRayNamespaces...)))). + WithPorts( + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(8265)), + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(10001)), + ), + networkingv1ac.NetworkPolicyIngressRule(). + WithPorts( + networkingv1ac.NetworkPolicyPort().WithProtocol(corev1.ProtocolTCP).WithPort(intstr.FromInt(8080)), + ). + WithFrom( + networkingv1ac.NetworkPolicyPeer().WithNamespaceSelector(metav1ac.LabelSelector(). + WithMatchExpressions(metav1ac.LabelSelectorRequirement(). + WithKey(corev1.LabelMetadataName). + WithOperator(metav1.LabelSelectorOpIn). + WithValues("openshift-monitoring"))), + ), + networkingv1ac.NetworkPolicyIngressRule(). + WithPorts( + allSecuredPorts..., + ), + ), + ). + WithOwnerReferences( + metav1ac.OwnerReference().WithUID(cluster.UID).WithName(cluster.Name).WithKind(cluster.Kind).WithAPIVersion(cluster.APIVersion), + ) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *RayClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { + r.kubeClient = kubernetes.NewForConfigOrDie(mgr.GetConfig()) + r.routeClient = routev1client.NewForConfigOrDie(mgr.GetConfig()) + b := make([]byte, 16) + _, err := rand.Read(b) + if err != nil { + return err + } + r.CookieSalt = string(b) + return ctrl.NewControllerManagedBy(mgr). + Named(controllerName). + For(&rayv1.RayCluster{}). + Complete(r) +} diff --git a/pkg/controllers/raycluster_controller_test.go b/pkg/controllers/raycluster_controller_test.go new file mode 100644 index 00000000..94958b33 --- /dev/null +++ b/pkg/controllers/raycluster_controller_test.go @@ -0,0 +1,170 @@ +/* +Copyright 2024. + +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 controllers + +import ( + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + routev1 "github.com/openshift/api/route/v1" +) + +var _ = Describe("RayCluster controller", func() { + Context("RayCluster controller test", func() { + var rayClusterName = "test-raycluster" + var namespaceName string + BeforeEach(func(ctx SpecContext) { + By("Creating a namespace for running the tests.") + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-", + }, + } + namespace, err := k8sClient.CoreV1().Namespaces().Create(ctx, namespace, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + DeferCleanup(func(ctx SpecContext) { + err := k8sClient.CoreV1().Namespaces().Delete(ctx, namespace.Name, metav1.DeleteOptions{}) + Expect(err).To(Not(HaveOccurred())) + }) + namespaceName = namespace.Name + + By("creating a basic instance of the RayCluster CR") + raycluster := &rayv1.RayCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: rayClusterName, + Namespace: namespace.Name, + }, + Spec: rayv1.RayClusterSpec{ + HeadGroupSpec: rayv1.HeadGroupSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{}, + }, + }, + RayStartParams: map[string]string{}, + }, + }, + } + _, err = rayClient.RayV1().RayClusters(namespace.Name).Create(ctx, raycluster, metav1.CreateOptions{}) + Expect(err).To(Not(HaveOccurred())) + }) + + AfterEach(func(ctx SpecContext) { + By("removing instances of the RayClusters used") + rayClusters, err := rayClient.RayV1().RayClusters(namespaceName).List(ctx, metav1.ListOptions{}) + Expect(err).To(Not(HaveOccurred())) + + for _, rayCluster := range rayClusters.Items { + err = rayClient.RayV1().RayClusters(namespaceName).Delete(ctx, rayCluster.Name, metav1.DeleteOptions{}) + Expect(err).To(Not(HaveOccurred())) + } + + Eventually(func() ([]rayv1.RayCluster, error) { + rayClusters, err := rayClient.RayV1().RayClusters(namespaceName).List(ctx, metav1.ListOptions{}) + return rayClusters.Items, err + }).WithTimeout(time.Second * 10).Should(BeEmpty()) + }) + + It("should have oauth finalizer set", func(ctx SpecContext) { + Eventually(func() ([]string, error) { + foundRayCluster, err := rayClient.RayV1().RayClusters(namespaceName).Get(ctx, rayClusterName, metav1.GetOptions{}) + return foundRayCluster.Finalizers, err + }).WithTimeout(time.Second * 10).Should(ContainElement(oAuthFinalizer)) + }, SpecTimeout(time.Second*10)) + + It("should create all oauth resources", func(ctx SpecContext) { + foundRayCluster, err := rayClient.RayV1().RayClusters(namespaceName).Get(ctx, rayClusterName, metav1.GetOptions{}) + Expect(err).To(Not(HaveOccurred())) + + Eventually(func() (*corev1.Secret, error) { + return k8sClient.CoreV1().Secrets(namespaceName).Get(ctx, oauthSecretNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).ShouldNot(BeNil()) + Eventually(func() (*corev1.Service, error) { + return k8sClient.CoreV1().Services(namespaceName).Get(ctx, oauthServiceNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).ShouldNot(BeNil()) + Eventually(func() (*corev1.ServiceAccount, error) { + return k8sClient.CoreV1().ServiceAccounts(namespaceName).Get(ctx, oauthServiceAccountNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).ShouldNot(BeNil()) + Eventually(func() (*rbacv1.ClusterRoleBinding, error) { + return k8sClient.RbacV1().ClusterRoleBindings().Get(ctx, crbNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).ShouldNot(BeNil()) + Eventually(func() (*routev1.Route, error) { + return routeClient.RouteV1().Routes(namespaceName).Get(ctx, dashboardNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).ShouldNot(BeNil()) + }) + + It("should set owner references for all resources", func(ctx SpecContext) { + foundRayCluster, err := rayClient.RayV1().RayClusters(namespaceName).Get(ctx, rayClusterName, metav1.GetOptions{}) + Expect(err).To(Not(HaveOccurred())) + + Eventually(func() (*corev1.Secret, error) { + return k8sClient.CoreV1().Secrets(namespaceName).Get(ctx, oauthSecretNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceKind, Equal("RayCluster"))) + Eventually(func() (*corev1.Secret, error) { + return k8sClient.CoreV1().Secrets(namespaceName).Get(ctx, oauthSecretNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceName, Equal(foundRayCluster.Name))) + Eventually(func() (*corev1.Service, error) { + return k8sClient.CoreV1().Services(namespaceName).Get(ctx, oauthServiceNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceKind, Equal("RayCluster"))) + Eventually(func() (*corev1.Service, error) { + return k8sClient.CoreV1().Services(namespaceName).Get(ctx, oauthServiceNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceName, Equal(foundRayCluster.Name))) + Eventually(func() (*corev1.ServiceAccount, error) { + return k8sClient.CoreV1().ServiceAccounts(namespaceName).Get(ctx, oauthServiceAccountNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceKind, Equal("RayCluster"))) + Eventually(func() (*corev1.ServiceAccount, error) { + return k8sClient.CoreV1().ServiceAccounts(namespaceName).Get(ctx, oauthServiceAccountNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceName, Equal(foundRayCluster.Name))) + Eventually(func() (*routev1.Route, error) { + return routeClient.RouteV1().Routes(namespaceName).Get(ctx, dashboardNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceKind, Equal("RayCluster"))) + Eventually(func() (*routev1.Route, error) { + return routeClient.RouteV1().Routes(namespaceName).Get(ctx, dashboardNameFromCluster(foundRayCluster), metav1.GetOptions{}) + }).WithTimeout(time.Second * 10).Should(WithTransform(OwnerReferenceName, Equal(foundRayCluster.Name))) + }) + + It("should remove CRB when the RayCluster is deleted", func(ctx SpecContext) { + foundRayCluster, err := rayClient.RayV1().RayClusters(namespaceName).Get(ctx, rayClusterName, metav1.GetOptions{}) + Expect(err).To(Not(HaveOccurred())) + + err = rayClient.RayV1().RayClusters(namespaceName).Delete(ctx, foundRayCluster.Name, metav1.DeleteOptions{}) + Expect(err).To(Not(HaveOccurred())) + + Eventually(func() error { + _, err := k8sClient.RbacV1().ClusterRoleBindings().Get(ctx, crbNameFromCluster(foundRayCluster), metav1.GetOptions{}) + return err + }).WithTimeout(time.Second * 10).Should(Satisfy(errors.IsNotFound)) + }) + + }) +}) + +func OwnerReferenceKind(meta metav1.Object) string { + return meta.GetOwnerReferences()[0].Kind +} + +func OwnerReferenceName(meta metav1.Object) string { + return meta.GetOwnerReferences()[0].Name +} diff --git a/pkg/controllers/raycluster_webhook.go b/pkg/controllers/raycluster_webhook.go new file mode 100644 index 00000000..eb530697 --- /dev/null +++ b/pkg/controllers/raycluster_webhook.go @@ -0,0 +1,443 @@ +/* +Copyright 2023. + +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 controllers + +import ( + "context" + "strconv" + + rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/project-codeflare/codeflare-operator/pkg/config" +) + +const ( + oauthProxyContainerName = "oauth-proxy" + oauthProxyVolumeName = "proxy-tls-secret" + initContainerName = "create-cert" +) + +// log is for logging in this package. +var rayclusterlog = logf.Log.WithName("raycluster-resource") + +func SetupRayClusterWebhookWithManager(mgr ctrl.Manager, cfg *config.KubeRayConfiguration) error { + rayClusterWebhookInstance := &rayClusterWebhook{ + Config: cfg, + } + return ctrl.NewWebhookManagedBy(mgr). + For(&rayv1.RayCluster{}). + WithDefaulter(rayClusterWebhookInstance). + WithValidator(rayClusterWebhookInstance). + Complete() +} + +// +kubebuilder:webhook:path=/mutate-ray-io-v1-raycluster,mutating=true,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create,versions=v1,name=mraycluster.ray.openshift.ai,admissionReviewVersions=v1 +// +kubebuilder:webhook:path=/validate-ray-io-v1-raycluster,mutating=false,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create;update,versions=v1,name=vraycluster.ray.openshift.ai,admissionReviewVersions=v1 + +type rayClusterWebhook struct { + Config *config.KubeRayConfiguration +} + +var _ webhook.CustomDefaulter = &rayClusterWebhook{} +var _ webhook.CustomValidator = &rayClusterWebhook{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (w *rayClusterWebhook) Default(ctx context.Context, obj runtime.Object) error { + rayCluster := obj.(*rayv1.RayCluster) + + if ptr.Deref(w.Config.RayDashboardOAuthEnabled, true) { + rayclusterlog.V(2).Info("Adding OAuth sidecar container") + rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers = upsert(rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers, oauthProxyContainer(rayCluster), withContainerName(oauthProxyContainerName)) + + rayCluster.Spec.HeadGroupSpec.Template.Spec.Volumes = upsert(rayCluster.Spec.HeadGroupSpec.Template.Spec.Volumes, oauthProxyTLSSecretVolume(rayCluster), withVolumeName(oauthProxyVolumeName)) + + rayCluster.Spec.HeadGroupSpec.Template.Spec.ServiceAccountName = rayCluster.Name + "-oauth-proxy" + } + + if ptr.Deref(w.Config.MTLSEnabled, true) { + rayclusterlog.V(2).Info("Adding create-cert Init Containers") + // HeadGroupSpec + + // Append the list of environment variables for the ray-head container + for _, envVar := range envVarList() { + rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers[0].Env = upsert(rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers[0].Env, envVar, withEnvVarName(envVar.Name)) + } + + // Append the create-cert Init Container + rayCluster.Spec.HeadGroupSpec.Template.Spec.InitContainers = upsert(rayCluster.Spec.HeadGroupSpec.Template.Spec.InitContainers, rayHeadInitContainer(rayCluster, w.Config.IngressDomain), withContainerName(initContainerName)) + + // Append the CA volumes + for _, caVol := range caVolumes(rayCluster) { + rayCluster.Spec.HeadGroupSpec.Template.Spec.Volumes = upsert(rayCluster.Spec.HeadGroupSpec.Template.Spec.Volumes, caVol, withVolumeName(caVol.Name)) + } + + // Append the certificate volume mounts + for _, mount := range certVolumeMounts() { + rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers[0].VolumeMounts = upsert(rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers[0].VolumeMounts, mount, byVolumeMountName) + } + + // WorkerGroupSpec + + // Append the list of environment variables for the worker container + for _, envVar := range envVarList() { + rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Containers[0].Env = upsert(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Containers[0].Env, envVar, withEnvVarName(envVar.Name)) + } + + // Append the CA volumes + for _, caVol := range caVolumes(rayCluster) { + rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Volumes = upsert(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Volumes, caVol, withVolumeName(caVol.Name)) + } + + // Append the certificate volume mounts + for _, mount := range certVolumeMounts() { + rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Containers[0].VolumeMounts = upsert(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Containers[0].VolumeMounts, mount, byVolumeMountName) + } + + // Append the create-cert Init Container + rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.InitContainers = upsert(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.InitContainers, rayWorkerInitContainer(), withContainerName(initContainerName)) + } + + return nil +} + +func (w *rayClusterWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + rayCluster := obj.(*rayv1.RayCluster) + + var warnings admission.Warnings + var allErrors field.ErrorList + + allErrors = append(allErrors, validateIngress(rayCluster)...) + + if ptr.Deref(w.Config.RayDashboardOAuthEnabled, true) { + allErrors = append(allErrors, validateOAuthProxyContainer(rayCluster)...) + allErrors = append(allErrors, validateOAuthProxyVolume(rayCluster)...) + allErrors = append(allErrors, validateHeadGroupServiceAccountName(rayCluster)...) + } + + return warnings, allErrors.ToAggregate() +} + +func (w *rayClusterWebhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + rayCluster := newObj.(*rayv1.RayCluster) + + var warnings admission.Warnings + var allErrors field.ErrorList + + if !rayCluster.DeletionTimestamp.IsZero() { + // Object is being deleted, skip validations + return nil, nil + } + + allErrors = append(allErrors, validateIngress(rayCluster)...) + + if ptr.Deref(w.Config.RayDashboardOAuthEnabled, true) { + allErrors = append(allErrors, validateOAuthProxyContainer(rayCluster)...) + allErrors = append(allErrors, validateOAuthProxyVolume(rayCluster)...) + allErrors = append(allErrors, validateHeadGroupServiceAccountName(rayCluster)...) + } + + // Init Container related errors + if ptr.Deref(w.Config.MTLSEnabled, true) { + allErrors = append(allErrors, validateHeadInitContainer(rayCluster, w.Config.IngressDomain)...) + allErrors = append(allErrors, validateWorkerInitContainer(rayCluster)...) + allErrors = append(allErrors, validateHeadEnvVars(rayCluster)...) + allErrors = append(allErrors, validateWorkerEnvVars(rayCluster)...) + allErrors = append(allErrors, validateCaVolumes(rayCluster)...) + } + return warnings, allErrors.ToAggregate() +} + +func (w *rayClusterWebhook) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + // Optional: Add delete validation logic here + return nil, nil +} + +func validateOAuthProxyContainer(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + if err := contains(rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers, oauthProxyContainer(rayCluster), byContainerName, + field.NewPath("spec", "headGroupSpec", "template", "spec", "containers"), + "OAuth Proxy container is immutable"); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors +} + +func validateOAuthProxyVolume(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + if err := contains(rayCluster.Spec.HeadGroupSpec.Template.Spec.Volumes, oauthProxyTLSSecretVolume(rayCluster), byVolumeName, + field.NewPath("spec", "headGroupSpec", "template", "spec", "volumes"), + "OAuth Proxy TLS Secret volume is immutable"); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors +} + +func validateIngress(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + if ptr.Deref(rayCluster.Spec.HeadGroupSpec.EnableIngress, false) { + allErrors = append(allErrors, field.Invalid( + field.NewPath("spec", "headGroupSpec", "enableIngress"), + rayCluster.Spec.HeadGroupSpec.EnableIngress, + "RayCluster with enableIngress set to true is not allowed")) + } + + return allErrors +} + +func validateHeadGroupServiceAccountName(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + if rayCluster.Spec.HeadGroupSpec.Template.Spec.ServiceAccountName != rayCluster.Name+"-oauth-proxy" { + allErrors = append(allErrors, field.Invalid( + field.NewPath("spec", "headGroupSpec", "template", "spec", "serviceAccountName"), + rayCluster.Spec.HeadGroupSpec.Template.Spec.ServiceAccountName, + "RayCluster head group service account is immutable")) + } + + return allErrors +} + +func oauthProxyContainer(rayCluster *rayv1.RayCluster) corev1.Container { + return corev1.Container{ + Name: oauthProxyContainerName, + Image: "registry.redhat.io/openshift4/ose-oauth-proxy@sha256:1ea6a01bf3e63cdcf125c6064cbd4a4a270deaf0f157b3eabb78f60556840366", + Ports: []corev1.ContainerPort{ + {ContainerPort: 8443, Name: "oauth-proxy"}, + }, + Env: []corev1.EnvVar{ + { + Name: "COOKIE_SECRET", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: rayCluster.Name + "-oauth-config", + }, + Key: "cookie_secret", + }, + }, + }, + }, + Args: []string{ + "--https-address=:8443", + "--provider=openshift", + "--openshift-service-account=" + rayCluster.Name + "-oauth-proxy", + "--upstream=http://localhost:8265", + "--tls-cert=/etc/tls/private/tls.crt", + "--tls-key=/etc/tls/private/tls.key", + "--cookie-secret=$(COOKIE_SECRET)", + "--openshift-delegate-urls={\"/\":{\"resource\":\"pods\",\"namespace\":\"default\",\"verb\":\"get\"}}", + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: oauthProxyVolumeName, + MountPath: "/etc/tls/private", + ReadOnly: true, + }, + }, + } +} + +func oauthProxyTLSSecretVolume(rayCluster *rayv1.RayCluster) corev1.Volume { + return corev1.Volume{ + Name: oauthProxyVolumeName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: rayCluster.Name + "-proxy-tls-secret", + }, + }, + } +} + +func certVolumeMounts() []corev1.VolumeMount { + return []corev1.VolumeMount{ + { + Name: "ca-vol", + MountPath: "/home/ray/workspace/ca", + ReadOnly: true, + }, + { + Name: "server-cert", + MountPath: "/home/ray/workspace/tls", + ReadOnly: false, + }, + } +} + +func envVarList() []corev1.EnvVar { + return []corev1.EnvVar{ + { + Name: "MY_POD_IP", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "status.podIP", + }, + }, + }, + { + Name: "RAY_USE_TLS", + Value: "1", + }, + { + Name: "RAY_TLS_SERVER_CERT", + Value: "/home/ray/workspace/tls/server.crt", + }, + { + Name: "RAY_TLS_SERVER_KEY", + Value: "/home/ray/workspace/tls/server.key", + }, + { + Name: "RAY_TLS_CA_CERT", + Value: "/home/ray/workspace/tls/ca.crt", + }, + } +} + +func caVolumes(rayCluster *rayv1.RayCluster) []corev1.Volume { + return []corev1.Volume{ + { + Name: "ca-vol", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: `ca-secret-` + rayCluster.Name, + }, + }, + }, + { + Name: "server-cert", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + } +} + +func rayHeadInitContainer(rayCluster *rayv1.RayCluster, domain string) corev1.Container { + rayClientRoute := "rayclient-" + rayCluster.Name + "-" + rayCluster.Namespace + "." + domain + // Service name for basic interactive + svcDomain := rayCluster.Name + "-head-svc." + rayCluster.Namespace + ".svc" + + initContainerHead := corev1.Container{ + Name: "create-cert", + Image: "quay.io/project-codeflare/ray:latest-py39-cu118", + Command: []string{ + "sh", + "-c", + `cd /home/ray/workspace/tls && openssl req -nodes -newkey rsa:2048 -keyout server.key -out server.csr -subj '/CN=ray-head' && printf "authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nsubjectAltName = @alt_names\n[alt_names]\nDNS.1 = 127.0.0.1\nDNS.2 = localhost\nDNS.3 = ${FQ_RAY_IP}\nDNS.4 = $(awk 'END{print $1}' /etc/hosts)\nDNS.5 = ` + rayClientRoute + `\nDNS.6 = ` + svcDomain + `">./domain.ext && cp /home/ray/workspace/ca/* . && openssl x509 -req -CA ca.crt -CAkey ca.key -in server.csr -out server.crt -days 365 -CAcreateserial -extfile domain.ext`, + }, + VolumeMounts: certVolumeMounts(), + } + return initContainerHead +} + +func rayWorkerInitContainer() corev1.Container { + initContainerWorker := corev1.Container{ + Name: "create-cert", + Image: "quay.io/project-codeflare/ray:latest-py39-cu118", + Command: []string{ + "sh", + "-c", + `cd /home/ray/workspace/tls && openssl req -nodes -newkey rsa:2048 -keyout server.key -out server.csr -subj '/CN=ray-head' && printf "authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nsubjectAltName = @alt_names\n[alt_names]\nDNS.1 = 127.0.0.1\nDNS.2 = localhost\nDNS.3 = ${FQ_RAY_IP}\nDNS.4 = $(awk 'END{print $1}' /etc/hosts)">./domain.ext && cp /home/ray/workspace/ca/* . && openssl x509 -req -CA ca.crt -CAkey ca.key -in server.csr -out server.crt -days 365 -CAcreateserial -extfile domain.ext`, + }, + VolumeMounts: certVolumeMounts(), + } + return initContainerWorker +} + +func validateHeadInitContainer(rayCluster *rayv1.RayCluster, domain string) field.ErrorList { + var allErrors field.ErrorList + + if err := contains(rayCluster.Spec.HeadGroupSpec.Template.Spec.InitContainers, rayHeadInitContainer(rayCluster, domain), byContainerName, + field.NewPath("spec", "headGroupSpec", "template", "spec", "initContainers"), + "create-cert Init Container is immutable"); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors +} + +func validateWorkerInitContainer(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + if err := contains(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.InitContainers, rayWorkerInitContainer(), byContainerName, + field.NewPath("spec", "workerGroupSpecs", "0", "template", "spec", "initContainers"), + "create-cert Init Container is immutable"); err != nil { + allErrors = append(allErrors, err) + } + + return allErrors +} + +func validateCaVolumes(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + for _, caVol := range caVolumes(rayCluster) { + if err := contains(rayCluster.Spec.HeadGroupSpec.Template.Spec.Volumes, caVol, byVolumeName, + field.NewPath("spec", "headGroupSpec", "template", "spec", "volumes"), + "ca-vol and server-cert Secret volumes are immutable"); err != nil { + allErrors = append(allErrors, err) + } + if err := contains(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Volumes, caVol, byVolumeName, + field.NewPath("spec", "workerGroupSpecs", "0", "template", "spec", "volumes"), + "ca-vol and server-cert Secret volumes are immutable"); err != nil { + allErrors = append(allErrors, err) + } + } + + return allErrors +} + +func validateHeadEnvVars(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + for _, envVar := range envVarList() { + if err := contains(rayCluster.Spec.HeadGroupSpec.Template.Spec.Containers[0].Env, envVar, byEnvVarName, + field.NewPath("spec", "headGroupSpec", "template", "spec", "containers", strconv.Itoa(0), "env"), + "RAY_TLS related environment variables are immutable"); err != nil { + allErrors = append(allErrors, err) + } + } + + return allErrors +} + +func validateWorkerEnvVars(rayCluster *rayv1.RayCluster) field.ErrorList { + var allErrors field.ErrorList + + for _, envVar := range envVarList() { + if err := contains(rayCluster.Spec.WorkerGroupSpecs[0].Template.Spec.Containers[0].Env, envVar, byEnvVarName, + field.NewPath("spec", "workerGroupSpecs", "0", "template", "spec", "containers", strconv.Itoa(0), "env"), + "RAY_TLS related environment variables are immutable"); err != nil { + allErrors = append(allErrors, err) + } + } + + return allErrors +} diff --git a/pkg/controllers/suite_test.go b/pkg/controllers/suite_test.go new file mode 100644 index 00000000..6828bdad --- /dev/null +++ b/pkg/controllers/suite_test.go @@ -0,0 +1,143 @@ +/* +Copyright 2023. + +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 controllers + +import ( + "context" + "io" + "net/http" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" + rayclient "github.com/ray-project/kuberay/ray-operator/pkg/client/clientset/versioned" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + routev1 "github.com/openshift/api/route/v1" + routeclient "github.com/openshift/client-go/route/clientset/versioned" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient *kubernetes.Clientset +var rayClient *rayclient.Clientset +var routeClient *routeclient.Clientset +var testEnv *envtest.Environment +var ctx context.Context +var cancel context.CancelFunc + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +const ( + RayClusterCRDFileDownload = "https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/crd/bases/ray.io_rayclusters.yaml" + RouteCRDFileDownload = "https://raw.githubusercontent.com/openshift/api/master/route/v1/zz_generated.crd-manifests/routes-Default.crd.yaml" +) + +var _ = BeforeSuite(func() { + ctx, cancel = context.WithCancel(context.Background()) + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + var err error + var fRoute, fRaycluster *os.File + + By("Creating and downloading necessary crds") + err = os.Mkdir("./test-crds", os.ModePerm) + Expect(err).ToNot(HaveOccurred()) + fRoute, err = os.Create("./test-crds/route.yaml") + Expect(err).ToNot(HaveOccurred()) + defer fRoute.Close() + resp, err := http.Get(RouteCRDFileDownload) + Expect(err).ToNot(HaveOccurred()) + _, err = io.Copy(fRoute, resp.Body) + Expect(err).ToNot(HaveOccurred()) + fRaycluster, err = os.Create("./test-crds/raycluster.yaml") + Expect(err).ToNot(HaveOccurred()) + defer fRaycluster.Close() + resp, err = http.Get(RayClusterCRDFileDownload) + Expect(err).ToNot(HaveOccurred()) + _, err = io.Copy(fRaycluster, resp.Body) + Expect(err).ToNot(HaveOccurred()) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join(".", "test-crds"), + }, + ErrorIfCRDPathMissing: true, + } + + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = kubernetes.NewForConfig(cfg) + Expect(err).NotTo(HaveOccurred()) + rayClient, err = rayclient.NewForConfig(cfg) + Expect(err).To(Not(HaveOccurred())) + routeClient, err = routeclient.NewForConfig(cfg) + Expect(err).NotTo(HaveOccurred()) + err = rayv1.AddToScheme(scheme.Scheme) + Expect(err).To(Not(HaveOccurred())) + err = routev1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + }) + Expect(err).NotTo(HaveOccurred()) + err = (&RayClusterReconciler{ + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + CookieSalt: "foo", + IsOpenShift: true, + }).SetupWithManager(k8sManager) + Expect(err).NotTo(HaveOccurred()) + go func() { + defer GinkgoRecover() + err = k8sManager.Start(ctx) + Expect(err).ToNot(HaveOccurred(), "failed to run manager") + }() +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := os.RemoveAll("./test-crds") + Expect(err).NotTo(HaveOccurred()) + cancel() + err = testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/pkg/controllers/support.go b/pkg/controllers/support.go new file mode 100644 index 00000000..d208b52d --- /dev/null +++ b/pkg/controllers/support.go @@ -0,0 +1,158 @@ +package controllers + +import ( + rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" + + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/validation/field" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" + networkingv1ac "k8s.io/client-go/applyconfigurations/networking/v1" + + routeapply "github.com/openshift/client-go/route/applyconfigurations/route/v1" +) + +func serviceNameFromCluster(cluster *rayv1.RayCluster) string { + return cluster.Name + "-head-svc" +} + +func desiredRayClientRoute(cluster *rayv1.RayCluster) *routeapply.RouteApplyConfiguration { + return routeapply.Route(rayClientNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithSpec(routeapply.RouteSpec(). + WithTo(routeapply.RouteTargetReference().WithKind("Service").WithName(serviceNameFromCluster(cluster)).WithWeight(100)). + WithPort(routeapply.RoutePort().WithTargetPort(intstr.FromString("client"))). + WithTLS(routeapply.TLSConfig().WithTermination("passthrough")), + ). + WithOwnerReferences( + v1.OwnerReference().WithUID(cluster.UID).WithName(cluster.Name).WithKind(cluster.Kind).WithAPIVersion(cluster.APIVersion), + ) +} + +func desiredRayClientIngress(cluster *rayv1.RayCluster, ingressHost string) *networkingv1ac.IngressApplyConfiguration { + return networkingv1ac.Ingress(rayClientNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/rewrite-target": "/", + "nginx.ingress.kubernetes.io/ssl-redirect": "true", + "nginx.ingress.kubernetes.io/ssl-passthrough": "true", + }). + WithOwnerReferences(v1.OwnerReference(). + WithAPIVersion(cluster.APIVersion). + WithKind(cluster.Kind). + WithName(cluster.Name). + WithUID(cluster.UID)). + WithSpec(networkingv1ac.IngressSpec(). + WithIngressClassName("nginx"). + WithRules(networkingv1ac.IngressRule(). + WithHost(ingressHost). + WithHTTP(networkingv1ac.HTTPIngressRuleValue(). + WithPaths(networkingv1ac.HTTPIngressPath(). + WithPath("/"). + WithPathType(networkingv1.PathTypeImplementationSpecific). + WithBackend(networkingv1ac.IngressBackend(). + WithService(networkingv1ac.IngressServiceBackend(). + WithName(serviceNameFromCluster(cluster)). + WithPort(networkingv1ac.ServiceBackendPort(). + WithNumber(10001), + ), + ), + ), + ), + ), + ), + ) +} + +func desiredClusterIngress(cluster *rayv1.RayCluster, ingressHost string) *networkingv1ac.IngressApplyConfiguration { + return networkingv1ac.Ingress(dashboardNameFromCluster(cluster), cluster.Namespace). + WithLabels(map[string]string{"ray.io/cluster-name": cluster.Name}). + WithOwnerReferences(v1.OwnerReference(). + WithAPIVersion(cluster.APIVersion). + WithKind(cluster.Kind). + WithName(cluster.Name). + WithUID(cluster.UID)). + WithSpec(networkingv1ac.IngressSpec(). + WithRules(networkingv1ac.IngressRule(). + WithHost(ingressHost). // Full Hostname + WithHTTP(networkingv1ac.HTTPIngressRuleValue(). + WithPaths(networkingv1ac.HTTPIngressPath(). + WithPath("/"). + WithPathType(networkingv1.PathTypePrefix). + WithBackend(networkingv1ac.IngressBackend(). + WithService(networkingv1ac.IngressServiceBackend(). + WithName(serviceNameFromCluster(cluster)). + WithPort(networkingv1ac.ServiceBackendPort(). + WithName(ingressServicePortName), + ), + ), + ), + ), + ), + ), + ) +} + +type compare[T any] func(T, T) bool + +func upsert[T any](items []T, item T, predicate compare[T]) []T { + for i, t := range items { + if predicate(t, item) { + items[i] = item + return items + } + } + return append(items, item) +} + +func contains[T any](items []T, item T, predicate compare[T], path *field.Path, msg string) *field.Error { + for _, t := range items { + if predicate(t, item) { + if equality.Semantic.DeepDerivative(item, t) { + return nil + } + return field.Invalid(path, t, msg) + } + } + return field.Required(path, msg) +} + +var byContainerName = compare[corev1.Container]( + func(c1, c2 corev1.Container) bool { + return c1.Name == c2.Name + }) + +func withContainerName(name string) compare[corev1.Container] { + return func(c1, c2 corev1.Container) bool { + return c1.Name == name + } +} + +var byVolumeName = compare[corev1.Volume]( + func(v1, v2 corev1.Volume) bool { + return v1.Name == v2.Name + }) + +func withVolumeName(name string) compare[corev1.Volume] { + return func(v1, v2 corev1.Volume) bool { + return v1.Name == name + } +} + +var byVolumeMountName = compare[corev1.VolumeMount]( + func(v1, v2 corev1.VolumeMount) bool { + return v1.Name == v2.Name + }) + +var byEnvVarName = compare[corev1.EnvVar]( + func(e1, e2 corev1.EnvVar) bool { + return e1.Name == e2.Name + }) + +func withEnvVarName(name string) compare[corev1.EnvVar] { + return func(e1, e2 corev1.EnvVar) bool { + return e1.Name == name + } +} diff --git a/test/e2e/kind.sh b/test/e2e/kind.sh new file mode 100755 index 00000000..7b7e9053 --- /dev/null +++ b/test/e2e/kind.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Copyright 2022 IBM, Red Hat +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -euo pipefail +: "${INGRESS_NGINX_VERSION:=controller-v1.9.6}" + +echo "Creating KinD cluster" +cat < 0 { + props.PipTrustedHost = "--trusted-host " + GetPipTrustedHost() + } + + template, err := files.ReadFile("resources/requirements.txt") + test.Expect(err).NotTo(HaveOccurred()) + + return ParseTemplate(test, template, props) +} + +func readMnistPy(test Test) []byte { + // Read the mnist.py from resources and perform replacements for custom values using go template + props := struct { + MnistDatasetURL string + }{ + MnistDatasetURL: GetMnistDatasetURL(), + } + template, err := files.ReadFile("resources/mnist.py") + test.Expect(err).NotTo(HaveOccurred()) + + return ParseTemplate(test, template, props) +} + +// TODO: This belongs on codeflare-common/support/ray.go +func rayClusters(t Test, namespace *corev1.Namespace) func(g gomega.Gomega) []*rayv1.RayCluster { + return func(g gomega.Gomega) []*rayv1.RayCluster { + rcs, err := t.Client().Ray().RayV1().RayClusters(namespace.Name).List(t.Ctx(), metav1.ListOptions{}) + g.Expect(err).NotTo(gomega.HaveOccurred()) + + rcsp := []*rayv1.RayCluster{} + for _, v := range rcs.Items { + rcsp = append(rcsp, &v) + } + + return rcsp + } +} diff --git a/test/odh/notebook.go b/test/odh/notebook.go new file mode 100644 index 00000000..70bdda82 --- /dev/null +++ b/test/odh/notebook.go @@ -0,0 +1,95 @@ +/* +Copyright 2023. + +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 odh + +import ( + "bytes" + + gomega "github.com/onsi/gomega" + . "github.com/project-codeflare/codeflare-common/support" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/yaml" + + imagev1 "github.com/openshift/api/image/v1" +) + +const recommendedTagAnnotation = "opendatahub.io/workbench-image-recommended" + +var notebookResource = schema.GroupVersionResource{Group: "kubeflow.org", Version: "v1", Resource: "notebooks"} + +type NotebookProps struct { + IngressDomain string + OpenShiftApiUrl string + KubernetesBearerToken string + Namespace string + OpenDataHubNamespace string + ImageStreamName string + ImageStreamTag string + RayImage string + NotebookConfigMapName string + NotebookConfigMapFileName string + NotebookPVC string +} + +func createNotebook(test Test, namespace *corev1.Namespace, notebookToken, jupyterNotebookConfigMapName, jupyterNotebookConfigMapFileName string) { + // Create PVC for Notebook + notebookPVC := CreatePersistentVolumeClaim(test, namespace.Name, "10Gi", corev1.ReadWriteOnce) + + // Retrieve ImageStream tag for + is := GetImageStream(test, GetOpenDataHubNamespace(), GetNotebookImageStreamName(test)) + recommendedTagName := getRecommendedImageStreamTag(test, is) + + // Read the Notebook CR from resources and perform replacements for custom values using go template + notebookProps := NotebookProps{ + IngressDomain: GetOpenShiftIngressDomain(test), + OpenShiftApiUrl: GetOpenShiftApiUrl(test), + KubernetesBearerToken: notebookToken, + Namespace: namespace.Name, + OpenDataHubNamespace: GetOpenDataHubNamespace(), + ImageStreamName: GetNotebookImageStreamName(test), + ImageStreamTag: recommendedTagName, + RayImage: GetRayImage(), + NotebookConfigMapName: jupyterNotebookConfigMapName, + NotebookConfigMapFileName: jupyterNotebookConfigMapFileName, + NotebookPVC: notebookPVC.Name, + } + notebookTemplate, err := files.ReadFile("resources/custom-nb-small.yaml") + test.Expect(err).NotTo(gomega.HaveOccurred()) + + parsedNotebookTemplate := ParseTemplate(test, notebookTemplate, notebookProps) + + // Create Notebook CR + notebookCR := &unstructured.Unstructured{} + err = yaml.NewYAMLOrJSONDecoder(bytes.NewBuffer(parsedNotebookTemplate), 8192).Decode(notebookCR) + test.Expect(err).NotTo(gomega.HaveOccurred()) + _, err = test.Client().Dynamic().Resource(notebookResource).Namespace(namespace.Name).Create(test.Ctx(), notebookCR, metav1.CreateOptions{}) + test.Expect(err).NotTo(gomega.HaveOccurred()) +} + +func getRecommendedImageStreamTag(test Test, is *imagev1.ImageStream) (tagName string) { + for _, tag := range is.Spec.Tags { + if tag.Annotations[recommendedTagAnnotation] == "true" { + return tag.Name + } + } + test.T().Fatalf("tag with annotation '%s' not found in ImageStream %s", recommendedTagAnnotation, is.Name) + return +} diff --git a/test/odh/resources/custom-nb-small.yaml b/test/odh/resources/custom-nb-small.yaml new file mode 100644 index 00000000..791a2d98 --- /dev/null +++ b/test/odh/resources/custom-nb-small.yaml @@ -0,0 +1,165 @@ +# This template maybe used to spin up a custom notebook image +# i.e.: sed s/{{.IngressDomain}}/$(oc get ingresses.config/cluster -o jsonpath={.spec.domain})/g tests/resources/custom-nb.template | oc apply -f - +# resources generated: +# pod/jupyter-nb-kube-3aadmin-0 +# service/jupyter-nb-kube-3aadmin +# route.route.openshift.io/jupyter-nb-kube-3aadmin (jupyter-nb-kube-3aadmin-opendatahub.apps.tedbig412.cp.fyre.ibm.com) +# service/jupyter-nb-kube-3aadmin-tls +apiVersion: kubeflow.org/v1 +kind: Notebook +metadata: + annotations: + notebooks.opendatahub.io/inject-oauth: "true" + notebooks.opendatahub.io/last-image-selection: codeflare-notebook:latest + notebooks.opendatahub.io/last-size-selection: Small + notebooks.opendatahub.io/oauth-logout-url: https://odh-dashboard-{{.OpenDataHubNamespace}}.{{.IngressDomain}}/notebookController/kube-3aadmin/home + opendatahub.io/link: https://jupyter-nb-kube-3aadmin-{{.Namespace}}.{{.IngressDomain}}/notebook/{{.Namespace}}/jupyter-nb-kube-3aadmin + opendatahub.io/username: kube:admin + generation: 1 + labels: + app: jupyter-nb-kube-3aadmin + opendatahub.io/dashboard: "true" + opendatahub.io/odh-managed: "true" + opendatahub.io/user: kube-3aadmin + name: jupyter-nb-kube-3aadmin + namespace: {{.Namespace}} +spec: + template: + spec: + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - preference: + matchExpressions: + - key: nvidia.com/gpu.present + operator: NotIn + values: + - "true" + weight: 1 + containers: + - env: + - name: NOTEBOOK_ARGS + value: |- + --ServerApp.port=8888 + --ServerApp.token='' + --ServerApp.password='' + --ServerApp.base_url=/notebook/{{.Namespace}}/jupyter-nb-kube-3aadmin + --ServerApp.quit_button=False + --ServerApp.tornado_settings={"user":"kube-3aadmin","hub_host":"https://odh-dashboard-{{.OpenDataHubNamespace}}.{{.IngressDomain}}","hub_prefix":"/notebookController/kube-3aadmin"} + - name: JUPYTER_IMAGE + value: image-registry.openshift-image-registry.svc:5000/{{.OpenDataHubNamespace}}/{{.ImageStreamName}}:{{.ImageStreamTag}} + - name: JUPYTER_NOTEBOOK_PORT + value: "8888" + - name: OCP_SERVER + value: {{.OpenShiftApiUrl}} + - name: OCP_TOKEN + value: {{.KubernetesBearerToken}} + image: image-registry.openshift-image-registry.svc:5000/{{.OpenDataHubNamespace}}/{{.ImageStreamName}}:{{.ImageStreamTag}} + command: ["/bin/sh", "-c", "pip install papermill && oc login --token=${OCP_TOKEN} --server=${OCP_SERVER} --insecure-skip-tls-verify=true && papermill /opt/app-root/notebooks/{{.NotebookConfigMapFileName}} /opt/app-root/src/mcad-out.ipynb -p namespace {{.Namespace}} -p ray_image {{.RayImage}} && sleep infinity"] + # args: ["pip install papermill && oc login --token=${OCP_TOKEN} --server=${OCP_SERVER} --insecure-skip-tls-verify=true && papermill /opt/app-root/notebooks/mcad.ipynb /opt/app-root/src/mcad-out.ipynb" ] + imagePullPolicy: Always + # livenessProbe: + # failureThreshold: 3 + # httpGet: + # path: /notebook/{{.Namespace}}/jupyter-nb-kube-3aadmin/api + # port: notebook-port + # scheme: HTTP + # initialDelaySeconds: 10 + # periodSeconds: 5 + # successThreshold: 1 + # timeoutSeconds: 1 + name: jupyter-nb-kube-3aadmin + ports: + - containerPort: 8888 + name: notebook-port + protocol: TCP + resources: + limits: + cpu: "2" + memory: 3Gi + requests: + cpu: "1" + memory: 3Gi + volumeMounts: + - mountPath: /opt/app-root/src + name: jupyterhub-nb-kube-3aadmin-pvc + - mountPath: /opt/app-root/notebooks + name: {{.NotebookConfigMapName}} + workingDir: /opt/app-root/src + - args: + - --provider=openshift + - --https-address=:8443 + - --http-address= + - --openshift-service-account=jupyter-nb-kube-3aadmin + - --cookie-secret-file=/etc/oauth/config/cookie_secret + - --cookie-expire=24h0m0s + - --tls-cert=/etc/tls/private/tls.crt + - --tls-key=/etc/tls/private/tls.key + - --upstream=http://localhost:8888 + - --upstream-ca=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + - --skip-auth-regex=^(?:/notebook/$(NAMESPACE)/jupyter-nb-kube-3aadmin)?/api$ + - --email-domain=* + - --skip-provider-button + - --openshift-sar={"verb":"get","resource":"notebooks","resourceAPIGroup":"kubeflow.org","resourceName":"jupyter-nb-kube-3aadmin","namespace":"$(NAMESPACE)"} + - --logout-url=https://odh-dashboard-{{.OpenDataHubNamespace}}.{{.IngressDomain}}/notebookController/kube-3aadmin/home + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: registry.redhat.io/openshift4/ose-oauth-proxy:v4.10 + imagePullPolicy: Always + livenessProbe: + failureThreshold: 3 + httpGet: + path: /oauth/healthz + port: oauth-proxy + scheme: HTTPS + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 1 + name: oauth-proxy + ports: + - containerPort: 8443 + name: oauth-proxy + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /oauth/healthz + port: oauth-proxy + scheme: HTTPS + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 100m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /etc/oauth/config + name: oauth-config + - mountPath: /etc/tls/private + name: tls-certificates + enableServiceLinks: false + serviceAccountName: jupyter-nb-kube-3aadmin + volumes: + - name: jupyterhub-nb-kube-3aadmin-pvc + persistentVolumeClaim: + claimName: {{.NotebookPVC}} + - name: oauth-config + secret: + defaultMode: 420 + secretName: jupyter-nb-kube-3aadmin-oauth-config + - name: tls-certificates + secret: + defaultMode: 420 + secretName: jupyter-nb-kube-3aadmin-tls + - name: {{.NotebookConfigMapName}} + configMap: + name: {{.NotebookConfigMapName}} diff --git a/test/odh/resources/mnist.py b/test/odh/resources/mnist.py new file mode 100644 index 00000000..85d420f4 --- /dev/null +++ b/test/odh/resources/mnist.py @@ -0,0 +1,190 @@ +# Copyright 2022 IBM, Red Hat +# +# 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. + +import os + +import torch +import requests +from pytorch_lightning import LightningModule, Trainer +from pytorch_lightning.callbacks.progress import TQDMProgressBar +from torch import nn +from torch.nn import functional as F +from torch.utils.data import DataLoader, random_split, RandomSampler +from torchmetrics import Accuracy +from torchvision import transforms +from torchvision.datasets import MNIST + +PATH_DATASETS = os.environ.get("PATH_DATASETS", ".") +BATCH_SIZE = 256 if torch.cuda.is_available() else 64 +# %% + +print("prior to running the trainer") +print("MASTER_ADDR: is ", os.getenv("MASTER_ADDR")) +print("MASTER_PORT: is ", os.getenv("MASTER_PORT")) + +MNIST_DATASET_URL = "{{.MnistDatasetURL}}" +print("MNIST_DATASET_URL: is ", MNIST_DATASET_URL) + +class LitMNIST(LightningModule): + def __init__(self, data_dir=PATH_DATASETS, hidden_size=64, learning_rate=2e-4): + + super().__init__() + + # Set our init args as class attributes + self.data_dir = data_dir + self.hidden_size = hidden_size + self.learning_rate = learning_rate + + # Hardcode some dataset specific attributes + self.num_classes = 10 + self.dims = (1, 28, 28) + channels, width, height = self.dims + self.transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize((0.1307,), (0.3081,)), + ] + ) + + # Define PyTorch model + self.model = nn.Sequential( + nn.Flatten(), + nn.Linear(channels * width * height, hidden_size), + nn.ReLU(), + nn.Dropout(0.1), + nn.Linear(hidden_size, hidden_size), + nn.ReLU(), + nn.Dropout(0.1), + nn.Linear(hidden_size, self.num_classes), + ) + + self.val_accuracy = Accuracy() + self.test_accuracy = Accuracy() + + def forward(self, x): + x = self.model(x) + return F.log_softmax(x, dim=1) + + def training_step(self, batch, batch_idx): + x, y = batch + logits = self(x) + loss = F.nll_loss(logits, y) + return loss + + def validation_step(self, batch, batch_idx): + x, y = batch + logits = self(x) + loss = F.nll_loss(logits, y) + preds = torch.argmax(logits, dim=1) + self.val_accuracy.update(preds, y) + + # Calling self.log will surface up scalars for you in TensorBoard + self.log("val_loss", loss, prog_bar=True) + self.log("val_acc", self.val_accuracy, prog_bar=True) + + def test_step(self, batch, batch_idx): + x, y = batch + logits = self(x) + loss = F.nll_loss(logits, y) + preds = torch.argmax(logits, dim=1) + self.test_accuracy.update(preds, y) + + # Calling self.log will surface up scalars for you in TensorBoard + self.log("test_loss", loss, prog_bar=True) + self.log("test_acc", self.test_accuracy, prog_bar=True) + + def configure_optimizers(self): + optimizer = torch.optim.Adam(self.parameters(), lr=self.learning_rate) + return optimizer + + #################### + # DATA RELATED HOOKS + #################### + + def prepare_data(self): + datasetFiles = [ + "t10k-images-idx3-ubyte", + "t10k-labels-idx1-ubyte", + "train-images-idx3-ubyte", + "train-labels-idx1-ubyte" + ] + + # Create required folder structure + downloadLocation = os.path.join(PATH_DATASETS, "MNIST", "raw") + os.makedirs(downloadLocation, exist_ok=True) + print(f"{downloadLocation} folder_path created!") + + for file in datasetFiles: + print(f"Downloading MNIST dataset {file}... to path : {downloadLocation}") + response = requests.get(f"{MNIST_DATASET_URL}{file}", stream=True) + filePath = os.path.join(downloadLocation, file) + + #to download dataset file + try: + if response.status_code == 200: + open(filePath, 'wb').write(response.content) + print(f"{file}: Downloaded and saved zipped file to path - {filePath}") + else: + print(f"Failed to download file {file}") + except Exception as e: + print(e) + print(f"Downloaded MNIST dataset to... {downloadLocation}") + + MNIST(self.data_dir, train=True, download=True) + MNIST(self.data_dir, train=False, download=True) + + def setup(self, stage=None): + + # Assign train/val datasets for use in dataloaders + if stage == "fit" or stage is None: + mnist_full = MNIST(self.data_dir, train=True, transform=self.transform) + self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000]) + + # Assign test dataset for use in dataloader(s) + if stage == "test" or stage is None: + self.mnist_test = MNIST( + self.data_dir, train=False, transform=self.transform + ) + + def train_dataloader(self): + return DataLoader(self.mnist_train, batch_size=BATCH_SIZE, sampler=RandomSampler(self.mnist_train, num_samples=1000)) + + def val_dataloader(self): + return DataLoader(self.mnist_val, batch_size=BATCH_SIZE) + + def test_dataloader(self): + return DataLoader(self.mnist_test, batch_size=BATCH_SIZE) + + +# Init DataLoader from MNIST Dataset + +model = LitMNIST() + +print("GROUP: ", int(os.environ.get("GROUP_WORLD_SIZE", 1))) +print("LOCAL: ", int(os.environ.get("LOCAL_WORLD_SIZE", 1))) + +# Initialize a trainer +trainer = Trainer( + accelerator="auto", + # devices=1 if torch.cuda.is_available() else None, # limiting got iPython runs + max_epochs=3, + callbacks=[TQDMProgressBar(refresh_rate=20)], + num_nodes=int(os.environ.get("GROUP_WORLD_SIZE", 1)), + devices=int(os.environ.get("LOCAL_WORLD_SIZE", 1)), + replace_sampler_ddp=False, + strategy="ddp", +) + +# Train the model ⚡ +trainer.fit(model) diff --git a/test/odh/resources/mnist_mcad_mini.ipynb b/test/odh/resources/mnist_mcad_mini.ipynb new file mode 100644 index 00000000..341eb12c --- /dev/null +++ b/test/odh/resources/mnist_mcad_mini.ipynb @@ -0,0 +1,95 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "b55bc3ea-4ce3-49bf-bb1f-e209de8ca47a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Import pieces from codeflare-sdk\n", + "from codeflare_sdk.job.jobs import DDPJobDefinition\n", + "from time import sleep" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47ca5c15", + "metadata": { + "tags": [ + "parameters" + ] + }, + "outputs": [], + "source": [ + "#parameters\n", + "namespace = \"default\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26b21373", + "metadata": {}, + "outputs": [], + "source": [ + "job = DDPJobDefinition(name=\"mnistjob\", script=\"/test/mnist.py\", scheduler_args={\"namespace\": namespace}, j=\"1x1\", gpu=0, cpu=1, memMB=2000, image=\"quay.io/project-codeflare/demo-images:pytorch-mnist-v0.0.1\").submit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d24e9f95", + "metadata": {}, + "outputs": [], + "source": [ + "finished = False\n", + "while not finished:\n", + " sleep(1)\n", + " try:\n", + " finished = (\"Epoch 2: 100%\" in job.logs())\n", + " except:\n", + " finished = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f078b7cd", + "metadata": {}, + "outputs": [], + "source": [ + "job.cancel()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "f9f85f796d01129d0dd105a088854619f454435301f6ffec2fea96ecbd9be4ac" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test/odh/resources/mnist_ray_mini.ipynb b/test/odh/resources/mnist_ray_mini.ipynb new file mode 100644 index 00000000..0d8fcc53 --- /dev/null +++ b/test/odh/resources/mnist_ray_mini.ipynb @@ -0,0 +1,146 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "b55bc3ea-4ce3-49bf-bb1f-e209de8ca47a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Import pieces from codeflare-sdk\n", + "from codeflare_sdk.cluster.cluster import Cluster, ClusterConfiguration\n", + "from codeflare_sdk.job.jobs import DDPJobDefinition\n", + "from time import sleep" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30888aed", + "metadata": { + "tags": [ + "parameters" + ] + }, + "outputs": [], + "source": [ + "#parameters\n", + "namespace = \"default\"\n", + "ray_image = \"has to be specified\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f4bc870-091f-4e11-9642-cba145710159", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Create our cluster and submit appwrapper\n", + "cluster = Cluster(ClusterConfiguration(namespace=namespace, name='mnisttest', head_cpus=1, head_memory=2, num_workers=1, min_cpus=1, max_cpus=1, min_memory=1, max_memory=2, num_gpus=0, instascale=False, image=ray_image))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0884bbc-c224-4ca0-98a0-02dfa09c2200", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Bring up the cluster\n", + "cluster.up()\n", + "cluster.wait_ready()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df71c1ed", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "cluster.status()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fd45bc5-03c0-4ae5-9ec5-dd1c30f1a084", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "cluster.details()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47ca5c15", + "metadata": {}, + "outputs": [], + "source": [ + "job = DDPJobDefinition(name=\"mnisttest\", script=\"mnist.py\", workspace=\"file:///opt/app-root/notebooks/..data\", scheduler_args={\"requirements\": \"/opt/app-root/notebooks/requirements.txt\"}).submit(cluster)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f63a178a", + "metadata": {}, + "outputs": [], + "source": [ + "finished = False\n", + "while not finished:\n", + " sleep(1)\n", + " status = job.status()\n", + " finished = (str(status.state) == \"SUCCEEDED\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b099777", + "metadata": {}, + "outputs": [], + "source": [ + "cluster.down()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "f9f85f796d01129d0dd105a088854619f454435301f6ffec2fea96ecbd9be4ac" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test/odh/resources/requirements.txt b/test/odh/resources/requirements.txt new file mode 100644 index 00000000..cf9fb588 --- /dev/null +++ b/test/odh/resources/requirements.txt @@ -0,0 +1,6 @@ +{{.PipIndexUrl}} +{{.PipTrustedHost}} +pytorch_lightning==1.5.10 +ray_lightning +torchmetrics==0.9.1 +torchvision==0.12.0 diff --git a/client/clientset/versioned/typed/codeflare/v1alpha1/generated_expansion.go b/test/odh/support.go similarity index 62% rename from client/clientset/versioned/typed/codeflare/v1alpha1/generated_expansion.go rename to test/odh/support.go index 4727cc4d..d828ed95 100644 --- a/client/clientset/versioned/typed/codeflare/v1alpha1/generated_expansion.go +++ b/test/odh/support.go @@ -14,10 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by client-gen. DO NOT EDIT. +package odh -package v1alpha1 +import ( + "embed" -type InstaScaleExpansion interface{} + "github.com/onsi/gomega" + "github.com/project-codeflare/codeflare-common/support" +) -type MCADExpansion interface{} +//go:embed resources/* +var files embed.FS + +func ReadFile(t support.Test, fileName string) []byte { + t.T().Helper() + file, err := files.ReadFile(fileName) + t.Expect(err).NotTo(gomega.HaveOccurred()) + return file +} diff --git a/test/odh/template.go b/test/odh/template.go new file mode 100644 index 00000000..3ff4da17 --- /dev/null +++ b/test/odh/template.go @@ -0,0 +1,40 @@ +/* +Copyright 2024. + +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 odh + +import ( + "bytes" + "html/template" + + "github.com/onsi/gomega" + "github.com/project-codeflare/codeflare-common/support" +) + +func ParseTemplate(t support.Test, inputTemplate []byte, props interface{}) []byte { + t.T().Helper() + + // Parse input template + parsedTemplate, err := template.New("template").Parse(string(inputTemplate)) + t.Expect(err).NotTo(gomega.HaveOccurred()) + + // Filter template and store results to the buffer + buffer := new(bytes.Buffer) + err = parsedTemplate.Execute(buffer, props) + t.Expect(err).NotTo(gomega.HaveOccurred()) + + return buffer.Bytes() +} diff --git a/test/pytorch_mnist_image/Dockerfile b/test/pytorch_mnist_image/Dockerfile new file mode 100644 index 00000000..adbbd7cb --- /dev/null +++ b/test/pytorch_mnist_image/Dockerfile @@ -0,0 +1,18 @@ +# Build the manager binary +FROM pytorch/pytorch:1.11.0-cuda11.3-cudnn8-runtime + +WORKDIR /test +COPY entrypoint.sh entrypoint.sh + +# Install MNIST requirements +COPY mnist_pip_requirements.txt requirements.txt +RUN pip install --requirement requirements.txt + +# Prepare MNIST script +COPY mnist.py mnist.py +COPY download_dataset.py download_dataset.py +RUN torchrun download_dataset.py + +USER 65532:65532 +WORKDIR /workdir +ENTRYPOINT ["/test/entrypoint.sh"] diff --git a/test/pytorch_mnist_image/download_dataset.py b/test/pytorch_mnist_image/download_dataset.py new file mode 100644 index 00000000..698f68f6 --- /dev/null +++ b/test/pytorch_mnist_image/download_dataset.py @@ -0,0 +1,21 @@ +# Copyright 2022 IBM, Red Hat +# +# 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. + +import os + +from torchvision.datasets import MNIST + +PATH_DATASETS = os.environ.get("PATH_DATASETS", ".") +MNIST(PATH_DATASETS, train=True, download=True) +MNIST(PATH_DATASETS, train=False, download=True) diff --git a/test/pytorch_mnist_image/entrypoint.sh b/test/pytorch_mnist_image/entrypoint.sh new file mode 100755 index 00000000..7487b377 --- /dev/null +++ b/test/pytorch_mnist_image/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +torchrun /test/mnist.py diff --git a/test/pytorch_mnist_image/mnist.py b/test/pytorch_mnist_image/mnist.py new file mode 100644 index 00000000..134d5618 --- /dev/null +++ b/test/pytorch_mnist_image/mnist.py @@ -0,0 +1,159 @@ +# Copyright 2022 IBM, Red Hat +# +# 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. + +import os + +import torch +import requests +from pytorch_lightning import LightningModule, Trainer +from pytorch_lightning.callbacks.progress import TQDMProgressBar +from torch import nn +from torch.nn import functional as F +from torch.utils.data import DataLoader, random_split +from torchmetrics import Accuracy +from torchvision import transforms +from torchvision.datasets import MNIST + +PATH_WORKDIR = os.environ.get("PATH_WORKDIR", ".") +PATH_DATASETS = os.environ.get("PATH_DATASETS", "/test") +BATCH_SIZE = 256 if torch.cuda.is_available() else 64 +# %% + +print("prior to running the trainer") +print("MASTER_ADDR: is ", os.getenv("MASTER_ADDR")) +print("MASTER_PORT: is ", os.getenv("MASTER_PORT")) + +class LitMNIST(LightningModule): + def __init__(self, data_dir=PATH_WORKDIR, hidden_size=64, learning_rate=2e-4): + + super().__init__() + + # Set our init args as class attributes + self.data_dir = data_dir + self.hidden_size = hidden_size + self.learning_rate = learning_rate + + # Hardcode some dataset specific attributes + self.num_classes = 10 + self.dims = (1, 28, 28) + channels, width, height = self.dims + self.transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize((0.1307,), (0.3081,)), + ] + ) + + # Define PyTorch model + self.model = nn.Sequential( + nn.Flatten(), + nn.Linear(channels * width * height, hidden_size), + nn.ReLU(), + nn.Dropout(0.1), + nn.Linear(hidden_size, hidden_size), + nn.ReLU(), + nn.Dropout(0.1), + nn.Linear(hidden_size, self.num_classes), + ) + + self.val_accuracy = Accuracy() + self.test_accuracy = Accuracy() + + def forward(self, x): + x = self.model(x) + return F.log_softmax(x, dim=1) + + def training_step(self, batch, batch_idx): + x, y = batch + logits = self(x) + loss = F.nll_loss(logits, y) + return loss + + def validation_step(self, batch, batch_idx): + x, y = batch + logits = self(x) + loss = F.nll_loss(logits, y) + preds = torch.argmax(logits, dim=1) + self.val_accuracy.update(preds, y) + + # Calling self.log will surface up scalars for you in TensorBoard + self.log("val_loss", loss, prog_bar=True) + self.log("val_acc", self.val_accuracy, prog_bar=True) + + def test_step(self, batch, batch_idx): + x, y = batch + logits = self(x) + loss = F.nll_loss(logits, y) + preds = torch.argmax(logits, dim=1) + self.test_accuracy.update(preds, y) + + # Calling self.log will surface up scalars for you in TensorBoard + self.log("test_loss", loss, prog_bar=True) + self.log("test_acc", self.test_accuracy, prog_bar=True) + + def configure_optimizers(self): + optimizer = torch.optim.Adam(self.parameters(), lr=self.learning_rate) + return optimizer + + #################### + # DATA RELATED HOOKS + #################### + + def prepare_data(self): + MNIST(PATH_DATASETS, train=True, download=True) + MNIST(PATH_DATASETS, train=False, download=True) + + def setup(self, stage=None): + + # Assign train/val datasets for use in dataloaders + if stage == "fit" or stage is None: + mnist_full = MNIST(PATH_DATASETS, train=True, transform=self.transform) + self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000]) + + # Assign test dataset for use in dataloader(s) + if stage == "test" or stage is None: + self.mnist_test = MNIST( + PATH_DATASETS, train=False, transform=self.transform + ) + + def train_dataloader(self): + return DataLoader(self.mnist_train, batch_size=BATCH_SIZE) + + def val_dataloader(self): + return DataLoader(self.mnist_val, batch_size=BATCH_SIZE) + + def test_dataloader(self): + return DataLoader(self.mnist_test, batch_size=BATCH_SIZE) + + +# Init DataLoader from MNIST Dataset + +model = LitMNIST() + +print("GROUP: ", int(os.environ.get("GROUP_WORLD_SIZE", 1))) +print("LOCAL: ", int(os.environ.get("LOCAL_WORLD_SIZE", 1))) + +# Initialize a trainer +trainer = Trainer( + accelerator="auto", + # devices=1 if torch.cuda.is_available() else None, # limiting got iPython runs + max_epochs=5, + callbacks=[TQDMProgressBar(refresh_rate=20)], + num_nodes=int(os.environ.get("GROUP_WORLD_SIZE", 1)), + devices=int(os.environ.get("LOCAL_WORLD_SIZE", 1)), + strategy="ddp", +) + +# Train the model ⚡ +trainer.fit(model) diff --git a/test/pytorch_mnist_image/mnist_pip_requirements.txt b/test/pytorch_mnist_image/mnist_pip_requirements.txt new file mode 100644 index 00000000..87edeef2 --- /dev/null +++ b/test/pytorch_mnist_image/mnist_pip_requirements.txt @@ -0,0 +1,3 @@ +pytorch_lightning==1.5.10 +torchmetrics==0.9.1 +torchvision==0.12.0